Mercurial Hosting > luan
changeset 1447:851b9a48cc44
Luan.parse
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 18 Feb 2020 14:54:35 -0700 |
parents | f2082e9aeaa9 |
children | 6fc083e1d08c |
files | src/luan/LuanTable.java src/luan/modules/Luan.luan src/luan/modules/lucene/LuceneIndex.java src/luan/modules/lucene/PostgresBackup.java src/luan/modules/parsers/LuanParser.java |
diffstat | 5 files changed, 312 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/LuanTable.java Tue Feb 11 13:38:55 2020 -0700 +++ b/src/luan/LuanTable.java Tue Feb 18 14:54:35 2020 -0700 @@ -279,6 +279,14 @@ mapToList(); } + public void rawAdd(Object value) { + check(); + if( value==null ) + throw new IllegalArgumentException("can't insert a nil value"); + list().add(value); + mapToList(); + } + public Object removeFromList(int pos) { check(); return list().remove(pos-1);
--- a/src/luan/modules/Luan.luan Tue Feb 11 13:38:55 2020 -0700 +++ b/src/luan/modules/Luan.luan Tue Feb 18 14:54:35 2020 -0700 @@ -1,5 +1,6 @@ require "java" local BasicLuan = require "java:luan.modules.BasicLuan" +local LuanParser = require "java:luan.modules.parsers.LuanParser" local Boot = require "luan:Boot.luan" local Luan = {} @@ -14,6 +15,7 @@ Luan.load_file = load_file Luan.new_error = BasicLuan.new_error Luan.pairs = BasicLuan.pairs +Luan.parse = LuanParser.parse Luan.pcall = BasicLuan.pcall Luan.range = BasicLuan.range Luan.raw_equal = BasicLuan.raw_equal
--- a/src/luan/modules/lucene/LuceneIndex.java Tue Feb 11 13:38:55 2020 -0700 +++ b/src/luan/modules/lucene/LuceneIndex.java Tue Feb 18 14:54:35 2020 -0700 @@ -846,7 +846,7 @@ } public void restore_from_postgres() - throws IOException, LuanException, SQLException + throws IOException, LuanException, SQLException, ParseException { if( postgresBackup!=null && wasCreated && !postgresBackup.wasCreated ) { luanLogger.error("restoring from postgres"); @@ -855,7 +855,7 @@ } public void force_restore_from_postgres() - throws IOException, LuanException, SQLException + throws IOException, LuanException, SQLException, ParseException { luanLogger.warn("start restore_from_postgres"); if( postgresBackup==null ) @@ -890,7 +890,7 @@ writer.addDocument(toLucene(doc,null)); } - public void check(LuanFunction completer) throws IOException, SQLException, LuanException { + public void check(LuanFunction completer) throws IOException, SQLException, LuanException, ParseException { boolean hasPostgres = postgresBackup != null; String msg = "start check"; if( hasPostgres ) @@ -905,7 +905,7 @@ } private void checkPostgres(LuanFunction completer) - throws IOException, SQLException, LuanException + throws IOException, SQLException, LuanException, ParseException { //luanLogger.info("start postgres check"); final PostgresBackup.Checker postgresChecker = postgresBackup.newChecker(); @@ -968,7 +968,7 @@ } private void checkPostgres(LuanFunction completer,PostgresBackup.Checker postgresChecker,LuanToString lts,long id) - throws IOException, SQLException, LuanException + throws IOException, SQLException, LuanException, ParseException { //luanLogger.info("check id "+id); writeLock.lock();
--- a/src/luan/modules/lucene/PostgresBackup.java Tue Feb 11 13:38:55 2020 -0700 +++ b/src/luan/modules/lucene/PostgresBackup.java Tue Feb 18 14:54:35 2020 -0700 @@ -17,6 +17,8 @@ import luan.LuanException; import luan.modules.Utils; import luan.modules.parsers.LuanToString; +import luan.modules.parsers.LuanParser; +import goodjava.parser.ParseException; import goodjava.logging.Logger; import goodjava.logging.LoggerFactory; @@ -156,26 +158,15 @@ con.setAutoCommit(true); } - private static LuanTable newEnv() { - LuanTable env = new LuanTable(new Luan()); - LuanToString.addNumberTypes(env); - return env; - } - - private static Object eval(String s,LuanTable env) throws LuanException { - LuanFunction fn = env.luan().load( "return "+s, "PostgresBackup", false, env ); - return fn.call(); - } - void restoreLucene(LuceneIndex li) - throws LuanException, IOException, SQLException + throws LuanException, IOException, SQLException, ParseException { - LuanTable env = newEnv(); + Luan luan = new Luan(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select data from lucene"); while( rs.next() ) { String data = rs.getString("data"); - LuanTable doc = (LuanTable)eval(data,env); + LuanTable doc = (LuanTable)LuanParser.parse(luan,data); li.restore(doc); } stmt.close(); @@ -195,7 +186,7 @@ final class Checker { private final Connection con; private final PreparedStatement pstmt; - private final LuanTable env = newEnv(); + private final Luan luan = new Luan(); Checker() throws SQLException { con = newConnection(); @@ -222,13 +213,13 @@ return ids; } - LuanTable getDoc(long id) throws SQLException, LuanException { + LuanTable getDoc(long id) throws SQLException, ParseException { pstmt.setLong(1,id); ResultSet rs = pstmt.executeQuery(); if( !rs.next() ) return null; String data = rs.getString("data"); - LuanTable doc = (LuanTable)eval(data,env); + LuanTable doc = (LuanTable)LuanParser.parse(luan,data); return doc; } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/modules/parsers/LuanParser.java Tue Feb 18 14:54:35 2020 -0700 @@ -0,0 +1,289 @@ +package luan.modules.parsers; + +import goodjava.parser.Parser; +import goodjava.parser.ParseException; +import luan.Luan; +import luan.LuanTable; +import luan.LuanException; + + +public final class LuanParser { + + public static Object parse(Luan luan,String text) throws ParseException { + return new LuanParser(luan,text).parse(); + } + + private static final Object NULL = new Object(); + private final Luan luan; + private final Parser parser; + + private LuanParser(Luan luan,String text) { + this.luan = luan; + this.parser = new Parser(text); + } + + private ParseException exception(String msg) { + return new ParseException(parser,msg); + } + + private Object parse() throws ParseException { + do { spaces(); } while( endOfLine() ); + Object value = requiredValue(); + do { spaces(); } while( endOfLine() ); + if( !parser.endOfInput() ) + throw exception("unexpected text"); + return value; + } + + private Object requiredValue() throws ParseException { + Object value = value(); + if( value == null ) + throw exception("invalid value"); + if( value == NULL ) + return null; + return value; + } + + private Object value() throws ParseException { + if( parser.match("nil") ) + return NULL; + if( parser.match("true") ) + return Boolean.TRUE; + if( parser.match("false") ) + return Boolean.FALSE; + String s = string(); + if( s != null ) + return s; + Number n = number(); + if( n != null ) + return n; + LuanTable tbl = table(); + if( tbl != null ) + return tbl; + return null; + } + + private String string() throws ParseException { + parser.begin(); + if( !parser.match('"') ) + return parser.failure(null); + StringBuilder sb = new StringBuilder(); + while( parser.anyChar() ) { + char c = parser.lastChar(); + switch(c) { + case '"': + return parser.success(sb.toString()); + case '\\': + if( parser.anyChar() ) { + c = parser.lastChar(); + switch(c) { + case '"': + case '\'': + case '\\': + sb.append(c); + continue; + case 'b': + sb.append('\b'); + continue; + case 'f': + sb.append('\f'); + continue; + case 'n': + sb.append('\n'); + continue; + case 'r': + sb.append('\r'); + continue; + case 't': + sb.append('\t'); + continue; + case 'u': + int n = 0; + for( int i=0; i<4; i++ ) { + int d; + if( parser.inCharRange('0','9') ) { + d = parser.lastChar() - '0'; + } else if( parser.inCharRange('a','f') ) { + d = parser.lastChar() - 'a' + 10; + } else if( parser.inCharRange('A','F') ) { + d = parser.lastChar() - 'A' + 10; + } else { + throw exception("invalid hex digit"); + } + n = 16*n + d; + } + sb.append((char)n); + continue; + } + } + throw exception("invalid escape char"); + default: + sb.append(c); + } + } + parser.failure(); + throw exception("unclosed string"); + } + + private Number number() { + parser.begin(); + if( parser.match("double") ) { + Number n = inParens(); + if( n==null ) + return parser.failure(null); + n = Luan.asDouble(n); + if( n==null ) + return parser.failure(null); + return n; + } else if( parser.match("float") ) { + Number n = inParens(); + if( n==null ) + return parser.failure(null); + n = Luan.asFloat(n); + if( n==null ) + return parser.failure(null); + return n; + } else if( parser.match("integer") ) { + Number n = inParens(); + if( n==null ) + return parser.failure(null); + n = Luan.asInteger(n); + if( n==null ) + return parser.failure(null); + return n; + } else if( parser.match("long") ) { + Number n = inParens(); + if( n==null ) + return parser.failure(null); + n = Luan.asLong(n); + if( n==null ) + return parser.failure(null); + return n; + } else { + Number n = untypedNumber(); + if( n != null ) + return parser.success(n); + else + return parser.failure(null); + } + } + + private Number inParens() { + spaces(); + if( !parser.match('(') ) + return null; + spaces(); + Number n = untypedNumber(); + if( n==null ) + return null; + spaces(); + if( !parser.match(')') ) + return null; + return n; + } + + private Number untypedNumber() { + int start = parser.begin(); + boolean isFloat = false; + parser.match('-'); + if( !parser.match('0') ) { + if( !parser.inCharRange('1','9') ) + return parser.failure(null); + while( parser.inCharRange('0','9') ); + } + if( parser.match('.') ) { + if( !parser.inCharRange('0','9') ) + return parser.failure(null); + while( parser.inCharRange('0','9') ); + isFloat = true; + } + if( parser.anyOf("eE") ) { + parser.anyOf("+-"); + if( !parser.inCharRange('0','9') ) + return parser.failure(null); + while( parser.inCharRange('0','9') ); + isFloat = true; + } + String s = parser.textFrom(start); + Number n; + if(isFloat) + n = Double.valueOf(s); + else + n = Long.valueOf(s); + return parser.success(n); + } + + private LuanTable table() throws ParseException { + parser.begin(); + if( !parser.match('{') ) + return parser.failure(null); + LuanTable tbl = new LuanTable(luan); + do { + spaces(); + Object obj = value(); + if( obj != null ) { + if( obj != NULL ) + tbl.rawAdd(obj); + spaces(); + continue; + } + Object key = key(); + if( key != null ) { + spaces(); + requiredMatch('='); + spaces(); + Object value = requiredValue(); + spaces(); + try { + tbl.rawPut(key,value); + } catch(LuanException e) { + throw new RuntimeException(e); + } + } + } while( fieldSep() ); + requiredMatch('}'); + return parser.success(tbl); + } + + private Object key() throws ParseException { + if( parser.match('[') ) { + spaces(); + Object key = requiredValue(); + spaces(); + requiredMatch(']'); + return key; + } + int start = parser.currentIndex(); + if( nameFirstChar() ) { + while( nameChar() ); + return parser.textFrom(start); + } + return null; + } + + private boolean nameChar() { + return nameFirstChar() || parser.inCharRange('0','9'); + } + + private boolean nameFirstChar() { + return parser.inCharRange('a','z') || parser.inCharRange('A','Z') || parser.match('_'); + } + + private boolean fieldSep() throws ParseException { + return parser.anyOf(",;") || endOfLine(); + } + + private boolean endOfLine() { + return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); + } + + private void requiredMatch(char c) throws ParseException { + if( !parser.match(c) ) + throw exception("'"+c+"' expected"); + } + + private void spaces() { + while( parser.anyOf(" \t") ); + } + +}