implement CSSparser; include "sys.m"; sys: Sys;include "string.m"; str: String;include "css.m"; css: CSS; Stylesheet, Statement, Select, Value: import css;include "cssparser.m"; init(){ sys = load Sys Sys->PATH; str = load String String->PATH; css = load CSS CSS->PATH; if (css == nil) { sys->fprint(sys->fildes(2), "cssparser: cannot load %s: %r\n", CSS->PATH); raise "fail:bad module"; } css->init(1);} parse(s: string): list of (string, list of Decl){ (stylesheet, e) := css->parse(s); if (stylesheet == nil) { warning("error parsing stylesheet: " + e); return nil; } rules, r: list of (string, list of Decl); for (stl := stylesheet.statements; stl != nil; stl = tl stl) { pick st := hd stl { Ruleset => rules = ruleset2rule(st, rules); } } for (; rules != nil; rules = tl rules) r = hd rules :: r; return r;} ruleset2rule(statement: ref Statement.Ruleset, onto: list of (string, list of Decl)): list of (string, list of Decl){ d := makedecls(statement.decls); names: list of string; for (sels := statement.selectors; sels != nil; sels = tl sels) { csel := hd sels; if (len csel != 1) { warning("context-specific selectors not allowed"); continue; } (nil, l) := hd csel; if ((name := selector2name(l)) != nil) names = name :: names; } for (; names != nil; names = tl names) onto = (hd names, d) :: onto; return onto;} makedecls(decls: list of ref CSS->Decl): list of Decl{ d: list of Decl; for (; decls != nil; decls = tl decls) { nd: Decl; nd.name = (hd decls).property; nd.important = (hd decls).important; s := ""; for (vals := (hd decls).values; vals != nil; vals = tl vals) { vs: string; pick v := hd vals { Percentage => vs = v.value + "%"; String or Number or Url or Unicoderange => vs = v.value; Hexcolour => vs = rgb2s(v.rgb); RGB => vs = rgb2s(v.rgb); Ident => vs = v.name; Unit => vs = v.value + v.units; } if (s != nil) s[len s] = (hd vals).sep; s += vs; } nd.val = s; d = nd :: d; } return d;} rgb2s(rgb: (int, int, int)): string{ (r, g, b) := rgb; return sys->sprint("#%.2x%.2x%.2x", r, g, b);} warning(s: string){ sys->fprint(sys->fildes(2), "cssparser: %s\n", s);} selector2name(sel: list of ref Select): string{ tag: string; class: string; pseudo: string; for (; sel != nil; sel = tl sel) { pick v := hd sel { Element => tag = v.name; Class => class = "." + v.name; Pseudo => class = ":" + v.name; * => warning("unknown selector type " + string tagof(hd sel)); } } return tag + class + pseudo;} parsedecl(s: string): list of Decl{ if (s == nil) return nil; (d, e) := css->parsedecl(s); if (d == nil) { warning(e); return nil; } return makedecls(d);}
implement CSSparser;
include "sys.m";
sys: Sys;
include "string.m";
str: String;
include "css.m";
css: CSS;
Stylesheet, Statement, Select, Value: import css;
include "cssparser.m";
init()
{
sys = load Sys Sys->PATH;
str = load String String->PATH;
css = load CSS CSS->PATH;
if (css == nil) {
sys->fprint(sys->fildes(2), "cssparser: cannot load %s: %r\n", CSS->PATH);
raise "fail:bad module";
}
css->init(1);
}
parse(s: string): list of (string, list of Decl)
{
(stylesheet, e) := css->parse(s);
if (stylesheet == nil) {
warning("error parsing stylesheet: " + e);
return nil;
}
rules, r: list of (string, list of Decl);
for (stl := stylesheet.statements; stl != nil; stl = tl stl) {
pick st := hd stl {
Ruleset =>
rules = ruleset2rule(st, rules);
}
}
for (; rules != nil; rules = tl rules)
r = hd rules :: r;
return r;
}
ruleset2rule(statement: ref Statement.Ruleset, onto: list of (string, list of Decl)): list of (string, list of Decl)
{
d := makedecls(statement.decls);
names: list of string;
for (sels := statement.selectors; sels != nil; sels = tl sels) {
csel := hd sels;
if (len csel != 1) {
warning("context-specific selectors not allowed");
continue;
}
(nil, l) := hd csel;
if ((name := selector2name(l)) != nil)
names = name :: names;
}
for (; names != nil; names = tl names)
onto = (hd names, d) :: onto;
return onto;
}
makedecls(decls: list of ref CSS->Decl): list of Decl
{
d: list of Decl;
for (; decls != nil; decls = tl decls) {
nd: Decl;
nd.name = (hd decls).property;
nd.important = (hd decls).important;
s := "";
for (vals := (hd decls).values; vals != nil; vals = tl vals) {
vs: string;
pick v := hd vals {
Percentage =>
vs = v.value + "%";
String or
Number or
Url or
Unicoderange =>
vs = v.value;
Hexcolour =>
vs = rgb2s(v.rgb);
RGB =>
vs = rgb2s(v.rgb);
Ident =>
vs = v.name;
Unit =>
vs = v.value + v.units;
}
if (s != nil)
s[len s] = (hd vals).sep;
s += vs;
}
nd.val = s;
d = nd :: d;
}
return d;
}
rgb2s(rgb: (int, int, int)): string
{
(r, g, b) := rgb;
return sys->sprint("#%.2x%.2x%.2x", r, g, b);
}
warning(s: string)
{
sys->fprint(sys->fildes(2), "cssparser: %s\n", s);
}
selector2name(sel: list of ref Select): string
{
tag: string;
class: string;
pseudo: string;
for (; sel != nil; sel = tl sel) {
pick v := hd sel {
Element =>
tag = v.name;
Class =>
class = "." + v.name;
Pseudo =>
class = ":" + v.name;
* =>
warning("unknown selector type " + string tagof(hd sel));
}
}
return tag + class + pseudo;
}
parsedecl(s: string): list of Decl
{
if (s == nil)
return nil;
(d, e) := css->parsedecl(s);
if (d == nil) {
warning(e);
return nil;
}
return makedecls(d);
}