From 79f31955a49d1e1fa1b17870db41e8e450e2c2b6 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Fri, 31 Aug 2012 14:13:43 +0000 Subject: [PATCH] Add grammer for lua 5.2 syntax and add unit test for LuaParser --- grammar/Lua52.jj | 364 ++++++++++++++++++ test/junit/org/luaj/vm2/AllTests.java | 2 + .../luaj/vm2/compiler/AbstractUnitTests.java | 18 +- .../org/luaj/vm2/compiler/LuaParserTests.java | 28 ++ 4 files changed, 409 insertions(+), 3 deletions(-) create mode 100644 grammar/Lua52.jj create mode 100644 test/junit/org/luaj/vm2/compiler/LuaParserTests.java diff --git a/grammar/Lua52.jj b/grammar/Lua52.jj new file mode 100644 index 00000000..819ef626 --- /dev/null +++ b/grammar/Lua52.jj @@ -0,0 +1,364 @@ +/** +* Javacc grammar for lua language version 5.1 +* +* Originally created for use in luaj, a Java implementation of the lua language +* @see http://sourceforge.net/projects/luaj/ +* +* For documentation on the lua language +* @see http://www.lua.org/manual/5.2/ +* +* Empty grammar that validates syntax without producing a parse tree. +* +* @author Jim Roseborough +* @date August 30, 2012 +*/ + +options { + STATIC = false; + JDK_VERSION = "1.3"; + ERROR_REPORTING = false; + DEBUG_LOOKAHEAD = false; + DEBUG_PARSER = false; + DEBUG_TOKEN_MANAGER = false; + OUTPUT_DIRECTORY = "org/luaj/vm2/parser"; +} + +PARSER_BEGIN(LuaParser) +package org.luaj.vm2.parser; + +public class LuaParser { + + public static void main(String args[]) throws ParseException { + LuaParser parser = new LuaParser(System.in); + parser.Chunk(); + } + + public static final int VAR = 0; + public static final int CALL = 1; +} + +PARSER_END(LuaParser) + +/* WHITE SPACE */ + +SKIP : +{ + " " | "\t" | "\n" | "\r" | "\f" +} + +/* COMMENTS and LONG STRINGS */ + +MORE : +{ + "--[[": IN_LC0 +| "--[=[": IN_LC1 +| "--[==[": IN_LC2 +| "--[===[": IN_LC3 +| < "--[====" ("=")* "[" > : IN_LCN +| "[[" : IN_LS0 +| "[=[" : IN_LS1 +| "[==[" : IN_LS2 +| "[===[" : IN_LS3 +| < "[====" ("=")* "[" > : IN_LSN +| "--" : IN_COMMENT +} + + SPECIAL_TOKEN : +{ + : DEFAULT +} + + SPECIAL_TOKEN : { : DEFAULT } + SPECIAL_TOKEN : { : DEFAULT } + SPECIAL_TOKEN : { : DEFAULT } + SPECIAL_TOKEN : { : DEFAULT } + SPECIAL_TOKEN : { : DEFAULT } + + TOKEN : { : DEFAULT } + TOKEN : { : DEFAULT } + TOKEN : { : DEFAULT } + TOKEN : { : DEFAULT } + TOKEN : { : DEFAULT } + + MORE : +{ + < ~[] > +} + + +/* RESERVED WORDS AND LITERALS */ + +TOKEN : +{ + +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +| +} + +/* LITERALS */ + +TOKEN : +{ + < NAME: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])* > +| < NUMBER: | > +| < #FLOAT: ()? > +| < #FNUM: ()+ "." ()* | "." ()+ | ()+ > +| < #DIGIT: ["0"-"9"] > +| < #EXP: ["e","E"] (["+","-"])? ()+ > +| < #HEX: "0" ["x","X"] ()? > +| < #HEXNUM: ()+ "." ()* | "." ()+ | ()+ > +| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] > +| < #HEXEXP: ["e","E","p","P"] (["+","-"])? ()+ > +| < STRING: "\"" ( | ~["\\","\""])* "\"" > +| < CHARSTRING: "'" ( | ~["\\","'"])* "'" > +| < #QUOTED: | | > +| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? > +| < DBCOLON: "::" > +| < SHEBANG: "#" ["!"," "] (~["\n","\r"])* ("\n"|"\r"|"\r\n") > +| < #UNICODE: "\\" "u" > +| < #CHAR: "\\" (~[]) > +| < #LF: ("\n" | "\r" | "\r\n") > +} + +/** Root production. */ +void Chunk(): +{} +{ + ( )? Block() +} + +void Block(): +{} +{ + ( Stat() )* ( ReturnStat() )? +} + +void Stat(): +{} +{ + ";" +| Label() +| +| +| Block() +| Exp() Block() +| Block() Exp() +| Exp() Block() ( Exp() Block())* ( Block())? +| LOOKAHEAD(3) "=" Exp() "," Exp() ( "," Exp() )? Block() +| NameList() ExpList() Block() +| FuncName() FuncBody() +| LOOKAHEAD(2) FuncBody() +| NameList() ( "=" ExpList() )? +| ExprStat() +} + +void ReturnStat(): +{} +{ + ( ExpList() )? ( ";" )? +} + +void Label(): +{} +{ + +} + +void ExprStat(): +{ int type,need=CALL; } +{ + type=PrimaryExp() ( Assign() { need=VAR; } )? + { if ( type!=need ) throw new ParseException("expected function call or assignment"); } +} + +void Assign(): +{} +{ + ( "," VarExp() )* "=" ExpList() +} + +void VarExp(): +{ int type; } +{ + type=PrimaryExp() + { if ( type!=VAR ) throw new ParseException("expected variable expression"); } +} + +void FuncName(): +{} +{ + ( "." )* ( ":" )? +} + +void PrefixExp(): +{} +{ + +| ParenExp() +} + +void ParenExp(): +{} +{ + "(" Exp() ")" +} + +int PrimaryExp(): +{ int type=VAR; } +{ + PrefixExp() ( LOOKAHEAD(2) type=PostfixOp() )* { return type; } +} + +int PostfixOp(): +{} +{ + FieldOp() { return VAR; } +| FuncOp() { return CALL; } +} + +void FieldOp(): +{} +{ + "." +| "[" Exp() "]" +} + +void FuncOp(): +{} +{ + ":" FuncArgs() +| FuncArgs() +} + +void FuncArgs(): +{} +{ + "(" ( ExpList() )? ")" +| TableConstructor() +| Str() +} + +void NameList(): +{} +{ + ( LOOKAHEAD(2) "," )* +} + +void ExpList(): +{} +{ + Exp() ( "," Exp() )* +} + +void SimpleExp(): +{} +{ + +| +| +| +| Str() +| "..." +| TableConstructor() +| FunctionCall() +| PrimaryExp() +} + +void Str(): +{} +{ + +| +| +| +| +| +| +} + +void Exp(): +{} +{ + SubExp() +} + +void SubExp(): +{} +{ + ( SimpleExp() | Unop() SubExp() ) (LOOKAHEAD(2) Binop() SubExp())* +} + +void FunctionCall(): +{} +{ + FuncBody() +} + +void FuncBody(): +{} +{ + "(" ( ParList() )? ")" Block() +} + +void ParList(): +{} +{ + NameList() ( "," "..." )? | "..." +} + +void TableConstructor(): +{} +{ + "{" ( FieldList() )? "}" +} + +void FieldList(): +{} +{ + Field() (LOOKAHEAD(2) FieldSep() Field())* (FieldSep())? +} + +void Field(): +{} +{ + "[" Exp() "]" "=" Exp() +| LOOKAHEAD(2) "=" Exp() +| Exp() +} + +void FieldSep(): +{} +{ + "," | ";" +} + +void Binop(): +{} +{ + "+" | "-" | "*" | "/" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | | +} + +void Unop(): +{} +{ + "-" | | "#" +} diff --git a/test/junit/org/luaj/vm2/AllTests.java b/test/junit/org/luaj/vm2/AllTests.java index 318fb5b6..7bede95b 100644 --- a/test/junit/org/luaj/vm2/AllTests.java +++ b/test/junit/org/luaj/vm2/AllTests.java @@ -29,6 +29,7 @@ import org.luaj.vm2.WeakTableTest.WeakKeyValueTableTest; import org.luaj.vm2.WeakTableTest.WeakValueTableTest; import org.luaj.vm2.compiler.CompilerUnitTests; import org.luaj.vm2.compiler.DumpLoadEndianIntTest; +import org.luaj.vm2.compiler.LuaParserTests; import org.luaj.vm2.compiler.RegressionTests; import org.luaj.vm2.compiler.SimpleTests; import org.luaj.vm2.lib.jse.LuaJavaCoercionTest; @@ -69,6 +70,7 @@ public class AllTests { TestSuite compiler = new TestSuite("Lua Compiler Tests"); compiler.addTestSuite(CompilerUnitTests.class); compiler.addTestSuite(DumpLoadEndianIntTest.class); + compiler.addTestSuite(LuaParserTests.class); compiler.addTestSuite(RegressionTests.class); compiler.addTestSuite(SimpleTests.class); suite.addTest(compiler); diff --git a/test/junit/org/luaj/vm2/compiler/AbstractUnitTests.java b/test/junit/org/luaj/vm2/compiler/AbstractUnitTests.java index 292a7e41..0d82a5b9 100644 --- a/test/junit/org/luaj/vm2/compiler/AbstractUnitTests.java +++ b/test/junit/org/luaj/vm2/compiler/AbstractUnitTests.java @@ -46,10 +46,23 @@ abstract public class AbstractUnitTests extends TestCase { _G = JsePlatform.standardGlobals(); } + protected String pathOfFile(String file) { + return jar + dir + "/" + file; + } + + protected InputStream inputStreamOfPath(String path) throws IOException { + URL url = new URL(path); + return url.openStream(); + } + + protected InputStream inputStreamOfFile(String file) throws IOException { + return inputStreamOfPath(pathOfFile(file)); + } + protected void doTest(String file) { try { // load source from jar - String path = jar + dir + "/" + file; + String path = pathOfFile(file); byte[] lua = bytesFromJar(path); // compile in memory @@ -83,8 +96,7 @@ abstract public class AbstractUnitTests extends TestCase { } protected byte[] bytesFromJar(String path) throws IOException { - URL url = new URL(path); - InputStream is = url.openStream(); + InputStream is = inputStreamOfPath(path); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int n; diff --git a/test/junit/org/luaj/vm2/compiler/LuaParserTests.java b/test/junit/org/luaj/vm2/compiler/LuaParserTests.java new file mode 100644 index 00000000..3c9c9d21 --- /dev/null +++ b/test/junit/org/luaj/vm2/compiler/LuaParserTests.java @@ -0,0 +1,28 @@ +package org.luaj.vm2.compiler; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.parser.LuaParser; + +public class LuaParserTests extends CompilerUnitTests { + + protected void setUp() throws Exception { + super.setUp(); + LuaValue.valueOf(true); + } + + protected void doTest(String file) { + try { + InputStream is = inputStreamOfFile(file); + Reader r = new InputStreamReader(is, "ISO-8859-1"); + LuaParser parser = new LuaParser(r); + parser.Chunk(); + } catch (Exception e) { + fail(e.getMessage()); + e.printStackTrace(); + } + } +}