Mercurial Hosting > luan
changeset 594:e91e476186c7
theme indentation
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 03 Sep 2015 12:23:53 -0600 |
parents | 92c9fa5e39e6 |
children | 8370c4009cce |
files | core/src/luan/impl/ExprImpl.java core/src/luan/impl/SetLocalVar.java core/src/luan/impl/ThemeParser.java |
diffstat | 3 files changed, 175 insertions(+), 65 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/impl/ExprImpl.java Thu Sep 03 12:23:53 2015 -0600 @@ -0,0 +1,11 @@ +package luan.impl; + +import luan.LuanElement; + + +abstract class ExprImpl extends CodeImpl implements Expr { + + ExprImpl(LuanElement el) { + super(el); + } +}
--- a/core/src/luan/impl/SetLocalVar.java Mon Aug 31 10:16:57 2015 -0600 +++ b/core/src/luan/impl/SetLocalVar.java Thu Sep 03 12:23:53 2015 -0600 @@ -5,6 +5,7 @@ private final int index; SetLocalVar(int index) { + if( index < 0 ) throw new RuntimeException(); this.index = index; }
--- a/core/src/luan/impl/ThemeParser.java Mon Aug 31 10:16:57 2015 -0600 +++ b/core/src/luan/impl/ThemeParser.java Thu Sep 03 12:23:53 2015 -0600 @@ -85,6 +85,7 @@ private static final String IO = "-IO-"; private static final String MOD = "-MOD-"; private static final String ENV = "-ENV-"; + private static final String INDENT = "-INDENT-"; private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; private final LuanSource source; @@ -122,6 +123,13 @@ return frame.stackIndex(name); } + private void popSymbols(int n) { + List<String> symbols = frame.symbols; + while( n-- > 0 ) { + symbols.remove(symbols.size()-1); + } + } + private int upValueIndex(String name) { return frame.upValueIndex(name); } @@ -148,7 +156,8 @@ { addSymbol(MOD); LuanElement se = se(0,"local M = {}"); - TableExpr tableExpr = new TableExpr( se, new TableExpr.Field[0], ExpList.emptyExpList ); + TableExpr.Field indent = new TableExpr.Field(new ConstExpr(null,INDENT),new ConstExpr(null,"")); + TableExpr tableExpr = new TableExpr( se, new TableExpr.Field[]{indent}, ExpList.emptyExpList ); SetStmt setStmt = new SetStmt( new SetLocalVar(stackIndex(MOD)), tableExpr ); stmts.add(setStmt); } @@ -166,117 +175,171 @@ return fnDef; } - private static class Tag { - final String name; - final Map<String,String> attrs; - - Tag(String name,Map<String,String> attrs) { - this.name = name; - this.attrs = attrs; - } - } - private Stmt parseDef() throws ParseException { int start = parser.begin(); if( !parser.match("{define:") ) return parser.failure(null); - Tag tag = parseBlockTag(); - if( tag == null ) - return parser.failure(null); - parser.match('\r'); parser.match('\n'); // ignore newline - if( !tag.attrs.isEmpty() ) + String name = parseName(); + if( name==null ) + throw exception("invalid block name"); + Map<String,String> attrs = parseAttrs(); + String spaces = ""; + if( BlankLine() ) { + while( BlankLine() ); + int startSpaces = parser.currentIndex(); + InlineSpaces(); + spaces = parser.textFrom(startSpaces); + } + if( !parser.match("}") ) + return null; + if( !attrs.isEmpty() ) throw exception("this block should have no attributes"); Expr table = new GetLocalVar(null,stackIndex(MOD)); - Settable fnName = new SetTableEntry(se(start),table,new ConstExpr(null,tag.name)); + Settable fnName = new SetTableEntry(se(start),table,new ConstExpr(null,name)); frame = new Frame(frame); addSymbol(ENV); - Stmt block = parseBody("define",tag); + Stmt block = parseBody("define:"+name,spaces,EndOfLine()); FnDef fnDef = newFnDef(start,block); frame = frame.parent; Stmt rtn = new SetStmt(fnName,fnDef); return parser.success(rtn); } - private Stmt parseBody(String type,Tag tag) throws ParseException { - String endTag = "{/"+type+":" + tag.name + "}"; + private Stmt parseBody(String tagName,String spaces,boolean initIndent) throws ParseException { List<Stmt> stmts = new ArrayList<Stmt>(); int stackStart = symbolsSize(); - StringBuilder sb = new StringBuilder(); - int start = -1; - while( !parser.match(endTag) ) { + int start = parser.currentIndex(); + { + addSymbol(INDENT); + final Expr env = env(); + Expr exp = new ExprImpl(se(start,"indent")) { + @Override public Object eval(LuanStateImpl luan) throws LuanException { + LuanTable tbl = (LuanTable)env.eval(luan); + String indent = (String)tbl.get(luan,INDENT); + if( indent==null ) throw new NullPointerException(); + return indent; + } + }; +// Expr exp = new IndexExpr( se(start,"indent"), env(), new ConstExpr(null,INDENT) ); + SetStmt setStmt = new SetStmt( new SetLocalVar(stackIndex(INDENT)), exp ); + stmts.add(setStmt); + } + boolean afterIndent = false; + if( initIndent && parser.match(spaces) ) { + addText(start,start,stmts,true); + start = parser.currentIndex(); + afterIndent = true; + } + int end = start; + while( !matchEndTag(tagName) ) { if( parser.endOfInput() ) throw exception("unclosed block"); - Stmt block = parseBlock(); + Stmt block = parseBlock(spaces); if( block != null ) { - addText(start,stmts,sb); + addText(start,end,stmts,false); + start = parser.currentIndex(); stmts.add(block); + afterIndent = false; continue; } - Stmt simpleTag = parseSimpleTag(); - if( simpleTag != null ) { - addText(start,stmts,sb); - stmts.add(simpleTag); + { + String extraSpaces = null; + if( afterIndent ) { + int startSpaces = parser.currentIndex(); + InlineSpaces(); + extraSpaces = parser.textFrom(startSpaces); + end = parser.currentIndex(); + } + Stmt simpleTag = parseSimpleTag(extraSpaces); + if( simpleTag != null ) { + addText(start,end,stmts,false); + start = parser.currentIndex(); + stmts.add(simpleTag); + afterIndent = false; + continue; + } + if( extraSpaces!=null && extraSpaces.length() > 0 ) + continue; + } + if( EndOfLine() ) { + end = parser.currentIndex(); + afterIndent = false; + if( parser.match(spaces) ) { + addText(start,end,stmts,true); + start = parser.currentIndex(); + afterIndent = true; + } continue; } - if( sb.length() == 0 ) - start = parser.currentIndex(); - sb.append( parser.currentChar() ); parser.anyChar(); + end = parser.currentIndex(); + afterIndent = false; } - addText(start,stmts,sb); - Stmt block = new Block( stmts.toArray(new Stmt[0]), 0, symbolsSize() ); + addText(start,end,stmts,false); + Stmt block = new Block( stmts.toArray(new Stmt[0]), stackStart, symbolsSize() ); + popSymbols(1); return block; } - private void addText(int start,List<Stmt> stmts,StringBuilder sb) { - if( sb.length() == 0 ) - return; - Expr io = new GetUpVar(null,upValueIndex(IO)); - Expr stdoutExp = new IndexExpr( se(start,"stdout"), io, new ConstExpr(null,"stdout") ); - Expr writeExp = new IndexExpr( se(start,"write"), stdoutExp, new ConstExpr(null,"write") ); - FnCall writeCall = new FnCall( se(start), writeExp, new ConstExpr(null,sb.toString()) ); - stmts.add( new ExpressionsStmt(writeCall) ); - sb.setLength(0); + private boolean matchEndTag(String tagName) { + parser.begin(); + if( !parser.match('{') ) + return parser.failure(); + Spaces(); + if( !(parser.match('/') && parser.match(tagName)) ) + return parser.failure(); + Spaces(); + if( !parser.match('}') ) + return parser.failure(); + return parser.success(); } - private Stmt parseBlock() throws ParseException { + private void addText(int start,int end,List<Stmt> stmts,boolean indent) { + List<Expressions> args = new ArrayList<Expressions>(); + if( start < end ) { + String text = parser.text.substring(start,end); + args.add( new ConstExpr(null,text) ); + } + if( indent ) { + args.add( new GetLocalVar(null,stackIndex(INDENT)) ); + } + if( !args.isEmpty() ) { + Expr io = new GetUpVar(null,upValueIndex(IO)); + Expr stdoutExp = new IndexExpr( se(start,"stdout"), io, new ConstExpr(null,"stdout") ); + Expr writeExp = new IndexExpr( se(start,"write"), stdoutExp, new ConstExpr(null,"write") ); + FnCall writeCall = new FnCall( se(start), writeExp, ExpList.build(args) ); + stmts.add( new ExpressionsStmt(writeCall) ); + } + } + + private Stmt parseBlock(String spaces) throws ParseException { int start = parser.begin(); if( !parser.match("{block:") ) return parser.failure(null); - Tag tag = parseBlockTag(); - if( tag == null ) - return parser.failure(null); - if( tag.name.equals("Set") ) - throw exception("block:Set not allowed here"); + String name = parseName(); + if( name==null ) + throw exception("invalid block name"); + Map<String,String> attrs = parseAttrs(); + if( !parser.match("}") ) + return null; frame = new Frame(frame); addSymbol(ENV); - Stmt block = parseBody("block",tag); + Stmt block = parseBody("block:"+name,spaces,false); FnDef fnDef = newFnDef(start,block); frame = frame.parent; // String rtn = "<% env." + tag.name + "(" + (tag.attrs.isEmpty() ? "nil" : table(tag.attrs)) + ",env,function(env) %>" + block + "<% end) %>"; Expr env = env(); - Expr fn = new IndexExpr( se(start,"block:"+tag.name), env, new ConstExpr(null,tag.name) ); + Expr fn = new IndexExpr( se(start,"block:"+name), env, new ConstExpr(null,name) ); List<Expressions> args = new ArrayList<Expressions>(); args.add( env ); - args.add( tag.attrs.isEmpty() ? new ConstExpr(null,null) : table(tag.attrs) ); + args.add( attrs.isEmpty() ? new ConstExpr(null,null) : table(attrs) ); args.add( fnDef ); FnCall fnCall = new FnCall( se(start), fn, ExpList.build(args) ); Stmt rtn = new ExpressionsStmt(fnCall); return parser.success(rtn); } - private Tag parseBlockTag() throws ParseException { - String name = parseName(); - if( name==null ) - throw exception("invalid block name"); - Map<String,String> attrs = parseAttrs(); - if( !parser.match("}") ) - return null; - Tag tag = new Tag(name,attrs); - return tag; - } - - private Stmt parseSimpleTag() throws ParseException { + private Stmt parseSimpleTag(String spaces) throws ParseException { int start = parser.begin(); if( !parser.match("{") ) return parser.failure(null); @@ -284,11 +347,29 @@ if( name==null ) return parser.failure(null); Map<String,String> attrs = parseAttrs(); + Spaces(); if( !parser.match("}") ) return parser.failure(null); // rtn = "<% env." + name + (attrs.isEmpty() ? "()" : table(attrs)) + " %>"; Expr env = env(); Expr fn = new IndexExpr( se(start,name), env, new ConstExpr(null,name) ); + if( spaces!=null && spaces.length() > 0 ) { + final Expr oldEnv = env; + final Expr oldIndentExpr = new GetLocalVar(null,stackIndex(INDENT)); + final String addSpaces = spaces; + env = new ExprImpl(se(start,"indent_env")) { + @Override public Object eval(LuanStateImpl luan) throws LuanException { + LuanTable mt = new LuanTable(); + mt.rawPut("__index",oldEnv.eval(luan)); + LuanTable tbl = new LuanTable(); + tbl.setMetatable(mt); + String oldIndent = (String)oldIndentExpr.eval(luan); + String newIndent = oldIndent + addSpaces; + tbl.rawPut(INDENT,newIndent); + return tbl; + } + }; + } List<Expressions> args = new ArrayList<Expressions>(); args.add( env ); if( !attrs.isEmpty() ) @@ -311,7 +392,6 @@ private Map<String,String> parseAttrs() { Map<String,String> attrs = new HashMap<String,String>(); while( parseAttr(attrs) ); - Spaces(); return attrs; } @@ -340,6 +420,24 @@ while( parser.anyOf(" \t\r\n") ); } + private void InlineSpaces() { + while( parser.anyOf(" \t") ); + } + + private void BlankLines() { + while( BlankLine() ); + } + + private boolean BlankLine() { + parser.begin(); + while( parser.anyOf(" \t") ); + return EndOfLine() ? parser.success() : parser.failure(); + } + + private boolean EndOfLine() { + return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); + } + private String parseName() { int start = parser.begin(); if( !NameChar() )