/****************************************************/ /* */ /* WAEBRIC PARSER */ /* */ /* http://code.google.com/p/waebric/ */ /* */ /* N.Heirbaut@cwi.nl */ /* */ /****************************************************/ ometa WaebricParser <: Parser { Modules = Module*:program end -> ['modules', program], Module = "module" spaces ModuleId:moduleId spaces ModuleElement*:moduleElement spaces -> ['module', moduleId, moduleElement], ModuleId = listOf(#IdCon, "."):moduleId -> ['module-id', moduleId.join('')], ModuleElement = Site:site | FunctionDef | Import, Import = "import" ModuleId:modId -> ['import', modId], Site = "site" spaces Mappings:mappings spaces "end" -> ['site', mappings], Mappings = listOf(#Mapping, ";"):mapping -> mapping | spaces, Mapping = spaces Path:path spaces ":" spaces Markup:markup spaces -> ['mapping', path, markup], Path = Directory:dir FileName:file -> ['path', "\"".concat(dir.toString().substring(0, dir.length - 1)).concat("\""), file] | FileName:file -> file, Directory = PathElement+:pathElement -> pathElement.join(''), PathElement = PathChar+:elem "/":sep -> elem.join('').concat(sep), PathChar = cRange('!', '-') | cRange('0','[') | cRange(']','~'), FileName = FileChar+:fileChar '.' FileExt:fileExt -> "\"".concat(fileChar.join('').concat('.').concat(fileExt.join(''))).concat("\""), FileChar = PathChar, FileExt = letterOrDigit+, Markup = spaces Designator:tag Arguments:args spaces -> ['call', tag, args] | spaces Designator:tag spaces -> tag, Designator = IdCon:idCon Attribute*:attr -> ['tag', idCon, attr], Attribute = "#" spaces IdCon:idCon -> ['id', idCon] | "." spaces IdCon:idClass -> ['class', idClass] | "$" spaces IdCon:idName -> ['name', idName] | ":" spaces IdCon:idType -> ['type', idType] | "@" spaces NatCon:width spaces "%" spaces NatCon:height -> ['width-height', width, height] | "@" spaces NatCon:width -> ['width', width], Arguments = "(" listOf(#Argument, ','):args ")" -> ['args', args] , Argument = spaces Var:idVar spaces "=" spaces Expression:expr -> ['attr', idVar, expr] | spaces Expression:expr -> expr, FunctionDef = "def" spaces IdCon:defId spaces Formals:formals spaces Statement*:stmts spaces "end" -> ['def', defId, formals, stmts] | "def" spaces IdCon:defId spaces Statement*:stmts spaces "end" -> ['def', defId, 'empty', stmts], Formals = "(" listOf(#IdCon, ','):list ")" -> ['formals', list], Expression = spaces Expression:expr spaces "." spaces IdCon:idCon ~"?" -> ['field', expr, idCon] | spaces Expression:expr1 spaces "+" spaces Expression:expr2 ~"?" -> ['cat', expr1, expr2] | spaces Text:idText spaces -> ['text', idText] | spaces Var:idVar spaces -> ['var', idVar] | spaces NatCon:idNatCon spaces -> ['num', idNatCon] | spaces SymbolCon:idSymbolCon spaces -> ['sym', idSymbolCon] | spaces "[" listOf(#Expression, ','):expr "]" -> ['list', expr] | spaces "{" listOf(#KeyValuePair, ','):record "}" -> ['record', record] , KeyValuePair = spaces IdCon:idCon spaces ":" Expression:expr -> ['pair', idCon, expr], Statement = "if" spaces "(" spaces Predicate:pred spaces ")" spaces Statement:stmt NoElseMayFollow -> ['if', pred, stmt] | "if" spaces "(" spaces Predicate:pred spaces ")" spaces Statement:ifStmt spaces "else" spaces Statement:elseStmt -> ['if-else', pred, ifStmt, elseStmt] | "each" spaces "(" spaces Var:varId spaces ":" spaces Expression:expr spaces ")" spaces Statement:stmt -> ['each', varId, expr, stmt] | "let" Assignment+:ass "in" Statement*:stmt "end" -> ['let', ass, stmt] | "{" spaces Statement*:stmts spaces "}" -> ['block', stmts] | "comment" spaces StrCon:comm spaces ";" -> ['comment', comm] | "echo" spaces '\"test\"' | "echo" spaces Expression:expr spaces ";" -> ['echo', expr] | "echo" spaces Embedding:emb spaces ";" -> ['echo-embedding', emb] | "cdata" spaces Expression:expr spaces ";" -> ['cdata', expr] | "yield" ";" -> ['yield'] | Markup:mrk ";" -> ['markup', mrk] | Markup+:mrk spaces ";" spaces ?(mrk[mrk.length -1][0] == 'tag') -> ['markup-expr', mrk.slice(0,mrk.length-1), ['var', mrk[mrk.length-1][1]]] | Markup+:mrk spaces ";" spaces ?(mrk.length >= 2) -> ['markup-markup', mrk] | Markup+:mrk spaces Expression:expr spaces ";" spaces -> ['markup-expr', mrk, expr] | Markup+:mrk spaces Statement:stmt -> ['markup-stat', mrk, stmt] | Markup+:mrk spaces Embedding:emb spaces ";" -> ['markup-embedding', mrk, emb] , NoElseMayFollow = ~"else", Predicate = "!" spaces Predicate:pred1 spaces -> ['not',pred1] | Predicate:pred1 spaces "&&" spaces Predicate:pred2 spaces -> ['and', pred1, pred2] | Predicate:pred1 spaces "||" spaces Predicate:pred2 spaces -> ['or', pred1, pred2] | Expression:expr "." Type:type "?" -> ['is-a', expr, type] | Expression, Type = "list" -> 'list-type' | "record" -> 'record-type' | "string" -> 'string-type', Assignment = spaces Var:varId spaces "=" spaces Expression:expr spaces ";" spaces -> ['var-bind', varId, expr] | IdCon:idCon "(" listOf(#IdCon, ','):frm ")" spaces "=" spaces Statement:stmt -> ['func-bind', idCon, frm, stmt], TextEntityRef = "&" XMLSymbol XML* ";", TextEntityRefHead = letter | "_" | ":", TextEntityRefTail = letterOrDigit | "." | "-" | "_" | ":", Text = '"':prefix (EscQuote | ~'"' TextChar)*:idText '"':suffix -> prefix.concat(idText.join('')).concat(suffix), TextChar = TextSymbolChar | Amp | TextCharRef | TextEntityRef | space, TextSymbolChar = cRange(' ','!') | cRange('#','%') | cRange('\'',';') | cRange('=','~'), TextCharRef = "&#" digit+ ";" | "&#x" HexaDecimal+ ";", Embedding = spaces PreText:pre spaces Embed:emb spaces TextTail:post spaces -> ['pre', pre,emb,post], Embed = Markup*:mrk spaces Expression:expr -> ['expr-embedding', mrk, expr] | Markup*:mrk ?(mrk[mrk.length -1][0] == 'tag') -> ['expr-embedding', mrk.slice(0,mrk.length-1), ['var', mrk[mrk.length-1][1]]] | Markup*:mrk -> ['markup-embedding', mrk], PreText = "\"" TextChar*:text "<" -> "\"".concat(text.join('')).concat("\""), PostText = ">" TextChar*:text "\"" -> "\"".concat(text.join('')).concat("\""), MidText = ">" TextChar*:text "<" -> "\"".concat(text.join('')).concat("\""), TextTail = PostText:text -> ['post', text] | MidText:mid Embed:embed TextTail:tail -> ['mid', mid, embed, tail], Var = IdCon , IdCon = spaces IdCharHead:head IdCharTail*:tail spaces ? ( (head.concat(tail.join('')) != 'if' ) &&(head.concat(tail.join('')) != 'comment' ) &&(head.concat(tail.join('')) != 'echo' ) &&(head.concat(tail.join('')) != 'cdata' ) &&(head.concat(tail.join('')) != 'each' ) &&(head.concat(tail.join('')) != 'let' ) &&(head.concat(tail.join('')) != 'yield' ) &&(head.concat(tail.join('')) != 'module' ) &&(head.concat(tail.join('')) != 'import' ) &&(head.concat(tail.join('')) != 'def' ) &&(head.concat(tail.join('')) != 'end' ) &&(head.concat(tail.join('')) != 'site' ) ) -> "\"".concat(head.concat(tail.join(''))).concat("\""), IdCharHead = letter, IdCharTail = letterOrDigit | '-', NatCon = digit+:d -> d.join('') , SymbolCon = "'":prefix SymbolChar*:idSymbolCon -> prefix.concat(idSymbolCon.join('')), SymbolChar = cRange('!','\(') | cRange('*','+') | cRange('-',':') | cRange('<','=') | cRange('?','~'), StrCon = "\"" StrChar*:str "\"" -> "\"".concat(str.join('')).concat("\""), StrChar = "\\n" | "\\t" | "\\\"" | "\\\\" | "\\" digit digit digit | cRange(' ','!') | cRange('#','[') | cRange(']', '~'), HexaDecimal = char:c ?((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')), Amp = "\&", Comment = fromTo('/*', '*/') | fromTo('//', '\n'), space = super(#space) | Comment, EscQuote = '\\' '\"' -> '\\\"', fromTo :x :y = seq(x) (~seq(y) char)* seq(y), cRange :x :y = char:c ?(c >= x) ?(c <= y) -> c } program = ' module menus site menus.html: main() end def main layout("Recursive Menus") { the-menu(); } end def css(url, media) link(rel="stylesheet", href=url, type="text/css", media=media); end def layout(title) html { head { css("blueprint.css", "screen, projection"); title title; } body yield; } end def the-menu menu({title: "Menu", kids: [{title: "Home", link: "/"}, {title: "Misc", kids: [{title: "Contact", link: "contact.html"}, {title: "Links", link: "links.html"}]}]}); end def menu(menu) echo menu.title; ul each (kid: menu.kids) item(kid); end def item(mi) li if (mi.kids) menu(mi); else a(href=mi.link) mi.title; end ' tree = WaebricParser.matchAll(program, "Modules") alert(tree)