diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/typedlua/tllexer.lua | 80 | ||||
| -rw-r--r-- | examples/typedlua/tlp.lua | 18 | ||||
| -rw-r--r-- | examples/typedlua/tlparser.lua | 228 |
3 files changed, 326 insertions, 0 deletions
diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua new file mode 100644 index 0000000..bcfa802 --- /dev/null +++ b/examples/typedlua/tllexer.lua | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | local tllexer = {} | ||
| 2 | |||
| 3 | local lpeg = require "lpeglabel" | ||
| 4 | lpeg.locale(lpeg) | ||
| 5 | |||
| 6 | local function setffp (s, i, t) | ||
| 7 | if not t.ffp or i > t.ffp then | ||
| 8 | t.ffp = i | ||
| 9 | end | ||
| 10 | return false | ||
| 11 | end | ||
| 12 | |||
| 13 | local function updateffp () | ||
| 14 | return lpeg.Cmt(lpeg.Carg(1), setffp) | ||
| 15 | end | ||
| 16 | |||
| 17 | tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n") | ||
| 18 | |||
| 19 | local Space = lpeg.space^1 | ||
| 20 | |||
| 21 | local Equals = lpeg.P("=")^0 | ||
| 22 | local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1 | ||
| 23 | local Close = "]" * lpeg.C(Equals) * "]" | ||
| 24 | local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"), | ||
| 25 | function (s, i, a, b) return a == b end) | ||
| 26 | |||
| 27 | local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * Close / | ||
| 28 | function (s, o) return s end | ||
| 29 | |||
| 30 | local Comment = lpeg.P("--") * LongString / | ||
| 31 | function () return end + | ||
| 32 | lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0 | ||
| 33 | |||
| 34 | tllexer.Skip = (Space + Comment)^0 | ||
| 35 | |||
| 36 | local idStart = lpeg.alpha + lpeg.P("_") | ||
| 37 | local idRest = lpeg.alnum + lpeg.P("_") | ||
| 38 | |||
| 39 | local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" + | ||
| 40 | "false" + "for" + "function" + "goto" + "if" + "in" + | ||
| 41 | "local" + "nil" + "not" + "or" + "repeat" + "return" + | ||
| 42 | "then" + "true" + "until" + "while" | ||
| 43 | |||
| 44 | tllexer.Reserved = Keywords * -idRest | ||
| 45 | |||
| 46 | local Identifier = idStart * idRest^0 | ||
| 47 | |||
| 48 | tllexer.Name = -tllexer.Reserved * Identifier * -idRest | ||
| 49 | |||
| 50 | function tllexer.token (pat) | ||
| 51 | return pat * tllexer.Skip + updateffp() * lpeg.P(false) | ||
| 52 | end | ||
| 53 | |||
| 54 | function tllexer.symb (str) | ||
| 55 | return tllexer.token(lpeg.P(str)) | ||
| 56 | end | ||
| 57 | |||
| 58 | function tllexer.kw (str) | ||
| 59 | return tllexer.token(lpeg.P(str) * -idRest) | ||
| 60 | end | ||
| 61 | |||
| 62 | local Hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.xdigit^1 | ||
| 63 | local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * lpeg.digit^1 | ||
| 64 | local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0) + | ||
| 65 | (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) + | ||
| 66 | (lpeg.digit^1 * Expo) | ||
| 67 | local Int = lpeg.digit^1 | ||
| 68 | |||
| 69 | tllexer.Number = Hex + Float + Int | ||
| 70 | |||
| 71 | local ShortString = lpeg.P('"') * | ||
| 72 | ((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 * | ||
| 73 | lpeg.P('"') + | ||
| 74 | lpeg.P("'") * | ||
| 75 | ((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 * | ||
| 76 | lpeg.P("'") | ||
| 77 | |||
| 78 | tllexer.String = LongString + ShortString | ||
| 79 | |||
| 80 | return tllexer | ||
diff --git a/examples/typedlua/tlp.lua b/examples/typedlua/tlp.lua new file mode 100644 index 0000000..4605751 --- /dev/null +++ b/examples/typedlua/tlp.lua | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | local tlparser = require "tlparser" | ||
| 2 | |||
| 3 | local function getcontents(filename) | ||
| 4 | file = assert(io.open(filename, "r")) | ||
| 5 | contents = file:read("*a") | ||
| 6 | file:close() | ||
| 7 | return contents | ||
| 8 | end | ||
| 9 | |||
| 10 | if #arg ~= 1 then | ||
| 11 | print ("Usage: lua tlp.lua <file>") | ||
| 12 | os.exit(1) | ||
| 13 | end | ||
| 14 | |||
| 15 | local filename = arg[1] | ||
| 16 | local subject = getcontents(filename) | ||
| 17 | |||
| 18 | print(tlparser.parse(subject, filename, false, true)) | ||
diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua new file mode 100644 index 0000000..002e580 --- /dev/null +++ b/examples/typedlua/tlparser.lua | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | local tlparser = {} | ||
| 2 | |||
| 3 | local lpeg = require "lpeglabel" | ||
| 4 | lpeg.locale(lpeg) | ||
| 5 | |||
| 6 | local tllexer = require "tllexer" | ||
| 7 | |||
| 8 | local function chainl1 (pat, sep) | ||
| 9 | return pat * (sep * pat)^0 | ||
| 10 | end | ||
| 11 | |||
| 12 | local G = lpeg.P { "TypedLua"; | ||
| 13 | TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * -1; | ||
| 14 | -- type language | ||
| 15 | Type = lpeg.V("NilableType"); | ||
| 16 | NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; | ||
| 17 | UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * lpeg.V("PrimaryType"))^0; | ||
| 18 | PrimaryType = lpeg.V("LiteralType") + | ||
| 19 | lpeg.V("BaseType") + | ||
| 20 | lpeg.V("NilType") + | ||
| 21 | lpeg.V("ValueType") + | ||
| 22 | lpeg.V("AnyType") + | ||
| 23 | lpeg.V("SelfType") + | ||
| 24 | lpeg.V("FunctionType") + | ||
| 25 | lpeg.V("TableType") + | ||
| 26 | lpeg.V("VariableType"); | ||
| 27 | LiteralType = tllexer.token("false") + | ||
| 28 | tllexer.token("true") + | ||
| 29 | tllexer.token(tllexer.Number) + | ||
| 30 | tllexer.token(tllexer.String); | ||
| 31 | BaseType = tllexer.token("boolean") + | ||
| 32 | tllexer.token("number") + | ||
| 33 | tllexer.token("string") + | ||
| 34 | tllexer.token("integer"); | ||
| 35 | NilType = tllexer.token("nil"); | ||
| 36 | ValueType = tllexer.token("value"); | ||
| 37 | AnyType = tllexer.token("any"); | ||
| 38 | SelfType = tllexer.token("self"); | ||
| 39 | FunctionType = lpeg.V("InputType") * tllexer.symb("->") * lpeg.V("NilableTuple"); | ||
| 40 | MethodType = lpeg.V("InputType") * tllexer.symb("=>") * lpeg.V("NilableTuple"); | ||
| 41 | InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); | ||
| 42 | NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; | ||
| 43 | UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * lpeg.V("OutputType"))^0; | ||
| 44 | OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); | ||
| 45 | TupleType = lpeg.V("Type") * (tllexer.symb(",") * lpeg.V("Type"))^0 * tllexer.symb("*")^-1; | ||
| 46 | TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.symb("}"); | ||
| 47 | TableTypeBody = lpeg.V("RecordType") + | ||
| 48 | lpeg.V("HashType") + | ||
| 49 | lpeg.V("ArrayType"); | ||
| 50 | RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * | ||
| 51 | (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; | ||
| 52 | RecordField = tllexer.kw("const")^-1 * | ||
| 53 | lpeg.V("LiteralType") * tllexer.symb(":") * lpeg.V("Type"); | ||
| 54 | HashType = lpeg.V("KeyType") * tllexer.symb(":") * lpeg.V("FieldType"); | ||
| 55 | ArrayType = lpeg.V("FieldType"); | ||
| 56 | KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); | ||
| 57 | FieldType = lpeg.V("Type"); | ||
| 58 | VariableType = tllexer.token(tllexer.Name); | ||
| 59 | RetType = lpeg.V("NilableTuple") + | ||
| 60 | lpeg.V("Type"); | ||
| 61 | Id = tllexer.token(tllexer.Name); | ||
| 62 | TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + | ||
| 63 | lpeg.V("Id"); | ||
| 64 | IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * lpeg.V("TypeDecId"))^0; | ||
| 65 | IdDec = lpeg.V("IdList") * tllexer.symb(":") * | ||
| 66 | (lpeg.V("Type") + lpeg.V("MethodType")); | ||
| 67 | IdDecList = (lpeg.V("IdDec")^1)^-1; | ||
| 68 | TypeDec = tllexer.token(tllexer.Name) * lpeg.V("IdDecList") * tllexer.kw("end"); | ||
| 69 | Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + | ||
| 70 | tllexer.kw("typealias") * tllexer.token(tllexer.Name) * tllexer.symb("=") * lpeg.V("Type"); | ||
| 71 | -- parser | ||
| 72 | Chunk = lpeg.V("Block"); | ||
| 73 | StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; | ||
| 74 | Var = lpeg.V("Id"); | ||
| 75 | TypedId = tllexer.token(tllexer.Name) * (tllexer.symb(":") * lpeg.V("Type"))^-1; | ||
| 76 | FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); | ||
| 77 | FieldSep = tllexer.symb(",") + tllexer.symb(";"); | ||
| 78 | Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) + | ||
| 79 | (tllexer.token(tllexer.Name))) * | ||
| 80 | tllexer.symb("=") * lpeg.V("Expr") + | ||
| 81 | lpeg.V("Expr"); | ||
| 82 | TField = (tllexer.kw("const") * lpeg.V("Field")) + | ||
| 83 | lpeg.V("Field"); | ||
| 84 | FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * | ||
| 85 | lpeg.V("FieldSep")^-1)^-1; | ||
| 86 | Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.symb("}"); | ||
| 87 | NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; | ||
| 88 | ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; | ||
| 89 | FuncArgs = tllexer.symb("(") * | ||
| 90 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * | ||
| 91 | tllexer.symb(")") + | ||
| 92 | lpeg.V("Constructor") + | ||
| 93 | tllexer.token(tllexer.String); | ||
| 94 | OrOp = tllexer.kw("or"); | ||
| 95 | AndOp = tllexer.kw("and"); | ||
| 96 | RelOp = tllexer.symb("~=") + | ||
| 97 | tllexer.symb("==") + | ||
| 98 | tllexer.symb("<=") + | ||
| 99 | tllexer.symb(">=") + | ||
| 100 | tllexer.symb("<") + | ||
| 101 | tllexer.symb(">"); | ||
| 102 | BOrOp = tllexer.symb("|"); | ||
| 103 | BXorOp = tllexer.symb("~"); | ||
| 104 | BAndOp = tllexer.symb("&"); | ||
| 105 | ShiftOp = tllexer.symb("<<") + | ||
| 106 | tllexer.symb(">>"); | ||
| 107 | ConOp = tllexer.symb(".."); | ||
| 108 | AddOp = tllexer.symb("+") + | ||
| 109 | tllexer.symb("-"); | ||
| 110 | MulOp = tllexer.symb("*") + | ||
| 111 | tllexer.symb("//") + | ||
| 112 | tllexer.symb("/") + | ||
| 113 | tllexer.symb("%"); | ||
| 114 | UnOp = tllexer.kw("not") + | ||
| 115 | tllexer.symb("-") + | ||
| 116 | tllexer.symb("~") + | ||
| 117 | tllexer.symb("#"); | ||
| 118 | PowOp = tllexer.symb("^"); | ||
| 119 | Expr = lpeg.V("SubExpr_1"); | ||
| 120 | SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp")); | ||
| 121 | SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp")); | ||
| 122 | SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp")); | ||
| 123 | SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp")); | ||
| 124 | SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp")); | ||
| 125 | SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp")); | ||
| 126 | SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp")); | ||
| 127 | SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * lpeg.V("SubExpr_8") + | ||
| 128 | lpeg.V("SubExpr_9"); | ||
| 129 | SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp")); | ||
| 130 | SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp")); | ||
| 131 | SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + | ||
| 132 | lpeg.V("SubExpr_12"); | ||
| 133 | SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; | ||
| 134 | SimpleExp = tllexer.token(tllexer.Number) + | ||
| 135 | tllexer.token(tllexer.String) + | ||
| 136 | tllexer.kw("nil") + | ||
| 137 | tllexer.kw("false") + | ||
| 138 | tllexer.kw("true") + | ||
| 139 | tllexer.symb("...") + | ||
| 140 | lpeg.V("FunctionDef") + | ||
| 141 | lpeg.V("Constructor") + | ||
| 142 | lpeg.V("SuffixedExp"); | ||
| 143 | SuffixedExp = lpeg.V("PrimaryExp") * ( | ||
| 144 | (tllexer.symb(".") * tllexer.token(tllexer.Name)) / "index" + | ||
| 145 | (tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) / "index" + | ||
| 146 | (tllexer.symb(":") * tllexer.token(tllexer.Name) * lpeg.V("FuncArgs")) / "call" + | ||
| 147 | lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; | ||
| 148 | PrimaryExp = lpeg.V("Var") / "var" + | ||
| 149 | tllexer.symb("(") * lpeg.V("Expr") * tllexer.symb(")"); | ||
| 150 | Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; | ||
| 151 | IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block") * | ||
| 152 | (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block"))^0 * | ||
| 153 | (tllexer.kw("else") * lpeg.V("Block"))^-1 * | ||
| 154 | tllexer.kw("end"); | ||
| 155 | WhileStat = tllexer.kw("while") * lpeg.V("Expr") * | ||
| 156 | tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); | ||
| 157 | DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); | ||
| 158 | ForBody = tllexer.kw("do") * lpeg.V("Block"); | ||
| 159 | ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * | ||
| 160 | lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * | ||
| 161 | lpeg.V("ForBody"); | ||
| 162 | ForGen = lpeg.V("NameList") * tllexer.kw("in") * | ||
| 163 | lpeg.V("ExpList") * lpeg.V("ForBody"); | ||
| 164 | ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.kw("end"); | ||
| 165 | RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * | ||
| 166 | tllexer.kw("until") * lpeg.V("Expr"); | ||
| 167 | FuncName = lpeg.V("Id") * (tllexer.symb(".") * | ||
| 168 | (tllexer.token(tllexer.Name)))^0 * | ||
| 169 | (tllexer.symb(":") * (tllexer.token(tllexer.Name)))^-1; | ||
| 170 | ParList = lpeg.V("NameList") * (tllexer.symb(",") * lpeg.V("TypedVarArg"))^-1 + | ||
| 171 | lpeg.V("TypedVarArg"); | ||
| 172 | TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * lpeg.V("Type"))^-1; | ||
| 173 | FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.symb(")") * | ||
| 174 | (tllexer.symb(":") * lpeg.V("RetType"))^-1 * | ||
| 175 | lpeg.V("Block") * tllexer.kw("end"); | ||
| 176 | FuncStat = tllexer.kw("const")^-1 * | ||
| 177 | tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); | ||
| 178 | LocalFunc = tllexer.kw("function") * | ||
| 179 | lpeg.V("Id") * lpeg.V("FuncBody"); | ||
| 180 | LocalAssign = lpeg.V("NameList") * | ||
| 181 | ((tllexer.symb("=") * lpeg.V("ExpList")))^-1; | ||
| 182 | LocalStat = tllexer.kw("local") * | ||
| 183 | (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); | ||
| 184 | LabelStat = tllexer.symb("::") * tllexer.token(tllexer.Name) * tllexer.symb("::"); | ||
| 185 | BreakStat = tllexer.kw("break"); | ||
| 186 | GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name); | ||
| 187 | RetStat = tllexer.kw("return") * | ||
| 188 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * | ||
| 189 | tllexer.symb(";")^-1; | ||
| 190 | TypeDecStat = lpeg.V("Interface"); | ||
| 191 | LocalTypeDec = lpeg.V("TypeDecStat"); | ||
| 192 | LVar = (tllexer.kw("const") * lpeg.V("SuffixedExp")) + | ||
| 193 | lpeg.V("SuffixedExp"); | ||
| 194 | ExprStat = lpeg.Cmt(lpeg.V("LVar") * lpeg.V("Assignment"), | ||
| 195 | function (s, i, ...) | ||
| 196 | local l = {...} | ||
| 197 | local i = 1 | ||
| 198 | while l[i] ~= "=" do | ||
| 199 | local se = l[i] | ||
| 200 | if se ~= "var" and se ~= "index" then return false end | ||
| 201 | i = i + 1 | ||
| 202 | end | ||
| 203 | return true | ||
| 204 | end) + | ||
| 205 | lpeg.Cmt(lpeg.V("SuffixedExp"), | ||
| 206 | function (s, i, se) | ||
| 207 | if se ~= "call" then return false end | ||
| 208 | return true | ||
| 209 | end); | ||
| 210 | Assignment = ((tllexer.symb(",") * lpeg.V("LVar"))^1)^-1 * (tllexer.symb("=") / "=") * lpeg.V("ExpList"); | ||
| 211 | Stat = lpeg.V("IfStat") + lpeg.V("WhileStat") + lpeg.V("DoStat") + lpeg.V("ForStat") + | ||
| 212 | lpeg.V("RepeatStat") + lpeg.V("FuncStat") + lpeg.V("LocalStat") + | ||
| 213 | lpeg.V("LabelStat") + lpeg.V("BreakStat") + lpeg.V("GoToStat") + | ||
| 214 | lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); | ||
| 215 | } | ||
| 216 | |||
| 217 | function tlparser.parse (subject, filename, strict, integer) | ||
| 218 | local errorinfo = {} | ||
| 219 | lpeg.setmaxstack(1000) | ||
| 220 | local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) | ||
| 221 | if not ast then | ||
| 222 | return nil | ||
| 223 | else | ||
| 224 | return true | ||
| 225 | end | ||
| 226 | end | ||
| 227 | |||
| 228 | return tlparser | ||
