def parse(tokens, pos=0): assert (isinstance(tokens, list)) assert (all(map(lambda x: isinstance(x, Tokenizer.TkAtom), tokens))) assert (isinstance(pos, int)) assert (pos < len(tokens)) full_geometry = tokens[pos].geometry values = [] while True: if isinstance(tokens[pos], Tokenizer.CallBeg): init_geometry = tokens[pos].geometry (pos, action) = parse(tokens, pos + 1) order_args = [] named_args = [] while not isinstance(tokens[pos], Tokenizer.CallEnd): (pos, new_arg) = parse(tokens, pos) if isinstance(tokens[pos], Tokenizer.CommonEqual): (pos, value) = parse(tokens, pos + 1) named_args.append(CallNamedArg(new_arg, value)) else: order_args.append(new_arg) geometry = init_geometry.expandTo(tokens[pos].geometry) values.append(Call(action, order_args, named_args, geometry)) elif isinstance(tokens[pos], Tokenizer.CallEnd): raise Exception('Invalid ")" character!') elif isinstance(tokens[pos], Tokenizer.Boolean): values.append(Boolean(tokens[pos].text, tokens[pos].geometry)) elif isinstance(tokens[pos], Tokenizer.Number): values.append(Number(tokens[pos].text, tokens[pos].geometry)) elif isinstance(tokens[pos], Tokenizer.Symbol): values.append(Symbol(tokens[pos].text, tokens[pos].geometry)) elif isinstance(tokens[pos], Tokenizer.String): values.append(String(tokens[pos].text, tokens[pos].geometry)) elif isinstance(tokens[pos], Tokenizer.StringEval): values.append(StringEval(tokens[pos].text, tokens[pos].geometry)) elif isinstance(tokens[pos], Tokenizer.FuncBeg): def testSyntax(token): if isinstance(token,Tokenizer.CommonEqual) or \ isinstance(token,Tokenizer.FuncName) or \ isinstance(token,Tokenizer.FuncStar) or \ isinstance(token,Tokenizer.FuncPlus): raise Exception('Invalid syntax for function call!') FUNC_ORDER = 0 FUNC_ORDER_DEFS = 1 FUNC_ORDER_VAR = 2 FUNC_NAMED = 3 FUNC_NAMED_DEFS = 4 FUNC_NAMED_VAR = 5 FUNC_STOP = 6 init_geometry = tokens[pos].geometry pos = pos + 1 cpos = 0 order = [] order_defs = [] order_var = None named = [] named_defs = [] named_var = None body = None contents = [] state = FUNC_ORDER while not isinstance(tokens[pos], Tokenizer.FuncEnd): if isinstance(tokens[pos], Tokenizer.CommonEqual): contents.append(tokens[pos]) pos = pos + 1 elif isinstance(tokens[pos], Tokenizer.FuncName): contents.append(tokens[pos]) pos = pos + 1 elif isinstance(tokens[pos], Tokenizer.FuncStar): contents.append(tokens[pos]) pos = pos + 1 elif isinstance(tokens[pos], Tokenizer.FuncPlus): contents.append(tokens[pos]) pos = pos + 1 else: (pos, new_item) = parse(tokens, pos) contents.append(new_item) if len(contents) < 1: raise Exception('Invalid empty function!') testSyntax(contents[-1]) body = contents[-1] del contents[-1] while cpos < len(contents) and state != FUNC_STOP: if state == FUNC_ORDER: if cpos + 3 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \ isinstance(contents[cpos+3],Tokenizer.FuncName): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_NAMED_DEFS named_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 4 elif cpos + 2 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_ORDER_DEFS order_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 3 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncName): testSyntax(contents[cpos]) state = FUNC_NAMED named.append(FuncArg(contents[cpos], None)) cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncStar): testSyntax(contents[cpos]) state = FUNC_ORDER_VAR order_var = contents[cpos] cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncPlus): testSyntax(contents[cpos]) state = FUNC_NAMED_VAR named_var = contents[cpos] cpos = cpos + 2 elif cpos < len(contents): testSyntax(contents[cpos]) state = FUNC_ORDER order.append(FuncArg(contents[cpos], None)) cpos = cpos + 1 else: state = FUNC_STOP elif state == FUNC_ORDER_DEFS: if cpos + 3 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \ isinstance(contents[cpos+3],Tokenizer.FuncName): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_NAMED_DEFS named_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 4 elif cpos + 2 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_ORDER_DEFS order_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 3 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncName): testSyntax(contents[cpos]) state = FUNC_NAMED named.append(FuncArg(contents[cpos], None)) cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncStar): testSyntax(contents[cpos]) state = FUNC_ORDER_VAR order_var = contents[cpos] cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncPlus): testSyntax(contents[cpos]) state = FUNC_NAMED_VAR named_var = contents[cpos] cpos = cpos + 2 elif cpos < len(contents): raise Exception( 'Cannot use order arguments after default ones!') else: state = FUNC_STOP elif state == FUNC_ORDER_VAR: if cpos + 3 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \ isinstance(contents[cpos+3],Tokenizer.FuncName): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_NAMED_DEFS named_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 4 elif cpos + 2 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual): raise Exception( 'Cannot use order arguments (with default) after variable one!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncName): testSyntax(contents[cpos]) state = FUNC_NAMED named.append(FuncArg(contents[cpos], None)) cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncStar): raise Exception( 'Only one variable order argument allowed!') elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncPlus): testSyntax(contents[cpos]) state = FUNC_NAMED_VAR named_var = contents[cpos] cpos = cpos + 2 elif cpos < len(contents): raise Exception( 'Cannot use order arguments after variable one!') else: state = FUNC_STOP elif state == FUNC_NAMED: if cpos + 3 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \ isinstance(contents[cpos+3],Tokenizer.FuncName): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_NAMED_DEFS named_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 4 elif cpos + 2 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual): raise Exception( 'Cannot use order arguments (with default) after named ones!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncName): testSyntax(contents[cpos]) state = FUNC_NAMED named.append(FuncArg(contents[cpos], None)) cpos = cpos + 2 elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncStar): raise Exception( 'Cannot use variable order argument after named ones!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncPlus): testSyntax(contents[cpos]) state = FUNC_NAMED_VAR named_var = contents[cpos] cpos = cpos + 2 elif cpos < len(contents): raise Exception( 'Cannot use order arguments after named ones!') else: state = FUNC_STOP elif state == FUNC_NAMED_DEFS: if cpos + 3 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual) and \ isinstance(contents[cpos+3],Tokenizer.FuncName): testSyntax(contents[cpos]) testSyntax(contents[cpos + 2]) state = FUNC_NAMED_DEFS named_defs.append( FuncArg(contents[cpos], contents[cpos + 2])) cpos = cpos + 4 elif cpos + 2 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.CommonEqual): raise Exception( 'Cannot use order arguments (with default) after named ones!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncName): raise Exception( 'Cannot use named arguments after default named arguments!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncStar): raise Exception( 'Cannot use variable order argument after named ones!' ) elif cpos + 1 < len(contents) and \ isinstance(contents[cpos+1],Tokenizer.FuncPlus): testSyntax(contents[cpos]) state = FUNC_NAMED_VAR named_var = contents[cpos] cpos = cpos + 2 elif cpos < len(contents): raise Exception( 'Cannot use order arguments after default ones!') else: state = FUNC_STOP elif state == FUNC_NAMED_VAR: if cpos < len(contents): raise Exception( 'Invalid argument after named variable one!') else: state = FUNC_STOP else: raise Exception('Critical Error: Invalid Func FSM Path!') if cpos != len(contents): raise Exception('Invalid syntax for function call!') geometry = init_geometry.expandTo(tokens[pos].geometry) values.append( Func(order, order_defs, order_var, named, named_defs, named_var, body, geometry)) elif isinstance(tokens[pos], Tokenizer.FuncEnd): raise Exception('Invalid "]" character!') elif isinstance(tokens[pos], Tokenizer.FuncName): raise Exception('Invalid "!" character!') elif isinstance(tokens[pos], Tokenizer.FuncStar): raise Exception('Invalid "*" character!') elif isinstance(tokens[pos], Tokenizer.FuncPlus): raise Exception('Invalid "+" character!') elif isinstance(tokens[pos], Tokenizer.BlockBeg): init_geometry = tokens[pos].geometry (pos, action) = parse(tokens, pos + 1) order_args = [] named_args = [] while not isinstance(tokens[pos], Tokenizer.BlockEnd): (pos, new_arg) = parse(tokens, pos) if isinstance(tokens[pos], Tokenizer.CommonEqual): (pos, value) = parse(tokens, pos + 1) named_args.append(CallNamedArg(new_arg, value)) else: order_args.append(new_arg) geometry = init_geometry.expandTo(tokens[pos].geometry) body = Call(action, order_args, named_args, geometry) values.append(Func([], [], None, [], [], None, body, geometry)) elif isinstance(tokens[pos], Tokenizer.BlockEnd): raise Exception('Invalid "}" character!') elif isinstance(tokens[pos], Tokenizer.DictBeg): init_geometry = tokens[pos].geometry pos = pos + 1 keyvalues = [] while not isinstance(tokens[pos], Tokenizer.DictEnd): (pos, key) = parse(tokens, pos) (pos, value) = parse(tokens, pos) keyvalues.append((key, value)) geometry = init_geometry.expandTo(tokens[pos].geometry) values.append(Dict(keyvalues, geometry)) elif isinstance(tokens[pos], Tokenizer.DictEnd): raise Exception('Invalid ">" character!') elif isinstance(tokens[pos], Tokenizer.DictBar): raise Exception('Invalid "|" character!') elif isinstance(tokens[pos], Tokenizer.CommonEqual): raise Exception('Invalid "=" character!') else: raise Exception('Invalid syntax!') pos = pos + 1 if pos < len(tokens) and isinstance(tokens[pos], Tokenizer.DictBar): pos = pos + 1 else: break if len(values) == 1: return (pos, values[0]) else: no_geom = Stream.Geometry(0, Stream.RelPos(0, 0), 0, Stream.RelPos(0, 0)) build_kvs = [(Symbol('Length', no_geom), Number(str(len(values)), no_geom))] for i in range(0, len(values)): build_kvs.append((Number(str(i), no_geom), values[i])) geometry = full_geometry.expandTo(tokens[pos - 1].geometry) return (pos, Dict(build_kvs, geometry))