// TODO: Work in progress #![allow(dead_code)] mod common; #[cfg(test)] mod lua_tests { use super::common::run_parser; use panfix::parsing::{Grammar, Parser}; use panfix::{juxtapose, op}; fn lua_parser() -> Parser { Grammar::new("LuaTest") .regex("Name", "[a-zA-Z_][a-zA-Z0-9_]*") .regex("Number", "(0|[1-9][0-9]*)(\\.[0-9]*)?") .regex("String", "\"[^\"]*\"") .constant("Nil", "nil") .constant("True", "true") .constant("False", "false") .constant("Ellipses", "...") .constant("Break", "break") .subgrammar("FuncName", |builder| { builder.op_r(op!(Colon: _ ":" _)).op_l(op!(Dot: _ "." _)) }) .subgrammar("Expr", |builder| { builder .op(op!(Do: "do" Expr "end")) .op(op!(While: "while" Expr "do" Expr "end")) .op(op!(If: "if" Expr "then" Expr "end")) .op(op!(For: "for" Expr "do" Expr "end")) .op(op!(Function: "function" FuncName "(" Expr ")" Expr "end")) .op(op!(Table: "{" Expr "}")) .op(op!(Parens: "(" Expr ")")) .op_r(op!(Exp: _ "^" _)) .ops_r(vec![op!(Not: "not" _), op!(Hash: "#" _), op!(Neg: "-" _)]) .ops_l(vec![ op!(Mul: _ "*" _), op!(Div: _ "/" _), op!(Mod: _ "%" _), ]) .ops_l(vec![op!(Add: _ "+" _), op!(Sub: _ "-" _)]) .op_l(op!(Range: _ ".." _)) .ops_l(vec![ op!(Lt: _ "<" _), op!(Gt: _ ">" _), op!(Lte: _ "<=" _), op!(Gte: _ ">=" _), op!(Neq: _ "~=" _), op!(Eq: _ "==" _), ]) .op_r(op!(And: _ "and" _)) .op_r(op!(Or: _ "or" _)) .op_r(op!(Colon: _ ":" _)) .ops_l(vec![ op!(Dot: _ "." _), op!(Get: _ "[" Expr "]"), op!(Call: _ "(" Expr ")"), op!(CallTable: _ "{" Expr "}"), juxtapose!(), ]) .op_r(op!(Comma: _ "," _)) .op_r(op!(Equals: _ "=" _)) .op(op!(Return: "return" _)) .ops_r(vec![ op!(Else: _ "else" _), op!(ElseIf: _ "elseif" Expr "then" _), op!(Repeat: _ "repeat" Expr "until" _), op!(Local: _ "local" _), ]) .op_r(op!(Semi: _ ";" _)) }) .build("Expr") } #[test] fn test_lua_parsing() { let parser = lua_parser(); let parse = |input: &str| run_parser(&parser, input); assert_eq!(parse(" 3 "), "3"); assert_eq!(parse("\"hello, world\""), "\"hello, world\""); assert_eq!(parse(" 3 "), "3"); assert_eq!(parse("Foobar"), "Foobar"); assert_eq!(parse("..."), "..."); assert_eq!(parse("do nil end"), "(do nil end)"); assert_eq!( parse("function...(false)break end"), "(function ... ( false ) break end)" ); assert_eq!(parse("(2+3)"), "(( (2 + 3) ))"); assert_eq!(parse("f(2+3)"), "(f ( (2 + 3) ))"); assert_eq!(parse("-2*3-2*3"), "(((- 2) * 3) - (2 * 3))"); assert_eq!(parse("a.b\"foo\""), "((a . b) ? \"foo\")"); } struct LuaProgram(Vec); type Block = Vec; type Name = String; enum Stmt { Block(Block), Assignment(Vec, Vec), If { cond: Box, r#then: Box, elseifs: Vec<(Expr, Expr)>, r#else: Option>, }, While(Box, Block), Repeat(Block, Box), For { name: Name, var: Box, limit: Box, step: Option>, block: Block, }, Call(Call), Local(Vec, Vec), } enum Expr { Binop(Box, Binop, Box), Unop(Unop, Box), Table(Vec), Call(Call), } enum Field { NamedField(Name, Box), NumberedField(Box), ExprField(Box, Box), } enum Var {} struct Call(); enum Binop { Exp, Mul, Div, Mod, Add, Sub, Lt, Gt, Lte, Gte, Eq, Neq, And, Or, Concat, } enum Unop { Not, Neg, Len, } }