from .structs import * from .exceptions import ParseError def parseDef(token, prev, tokens): if len(tokens) < 2: raise ParseError("invalid def", token.line) elif tokens[0].type_ != TokenType.SYMBOL: raise ParseError("'def' must take a symbol", token.line) sym, inc = parseSymbol(tokens[0], token, tokens[1:]) return NebDef(sym), inc + 1 def parseLambda(token, prev, tokens): # lambda [type] ( [arg] [&] ) [(expr)] # func [type] ( [arg] [&] ) [(expr)] idx = 0 sym = None return_type = Type(":any") if token.type_ == TokenType.FUNC: if tokens[idx].type_ != TokenType.SYMBOL: raise ParseError("'func' must take a symbol", tokens[idx].line) sym, counter = parseSymbol(tokens[idx], token, tokens[idx+1:]) idx += counter else: sym = Symbol("", token.line) if tokens[idx].type_ == TokenType.COLON: return_type, counter = parseType(tokens[idx], token, tokens[idx+1:]) idx += counter if tokens[idx].type_ != TokenType.OPEN_PAREN: raise ParseError("expecting argument list", tokens[idx].line) args, many, counter = parseFunctionArguments(tokens[idx:], tokens[idx-1], tokens[idx+1:]) idx += counter body = [] while tokens[idx].type_ != TokenType.CLOSE_PAREN: token = tokens[idx] counter = 1 if token.type_ == TokenType.OPEN_PAREN: expr, counter = parseExpression(token, prev, tokens[idx+1:]) body.append(expr) elif token.type_ in (TokenType.FALSE, TokenType.TRUE, TokenType.STRING, TokenType.INT, TokenType.FLOAT): lit, counter = parseLiteral(token, prev, tokens[idx+1:]) body.append(lit) elif token.type_ == TokenType.COLON: typ, counter = parseType(token, prev, tokens[idx+1:]) body.append(typ) else: inner_sym, counter = parseSymbol(token, prev, tokens[idx+1:]) body.append(inner_sym) idx += counter prev = token return NebFuncDef(sym, return_type, args, many, body), idx + 1 def parseFunctionArguments(token, prev, tokens): idx = 0 args = [] prev = token many = None prev_type = False first = True while tokens[idx].type_ != TokenType.CLOSE_PAREN: token = tokens[idx] if token.type_ == TokenType.SYMBOL: if many is not None: raise ParseError("& must be last argument", token.line) sym, counter = parseSymbol(token, prev, tokens) args.append(Arg(sym.name, TypeEnum.ANY)) prev_type = False counter = 1 elif token.type_ == TokenType.MANY: many = Arg("&", TypeEnum.ANY) prev_type = False counter = 1 elif token.type_ == TokenType.COLON and not prev_type and not first: if prev_type: raise ParseError("can't have two types in a row", token.line) if first: raise ParseError("type can't be first", token.line) typ, counter = parseType(token, prev, tokens[idx+1:]) if many is None: args[-1].type_ = typ else: many.type_ = typ prev_type = True else: raise ParseError("invalid function signature", token) first = False idx += counter # this should return function return args, many, idx + 2 # parens def parseExpression(token, prev, tokens): idx = 0 args = [] prev = token while tokens[idx].type_ != TokenType.CLOSE_PAREN: token = tokens[idx] if token.type_ == TokenType.EOF: raise ParseError("uneven parens: not enough closing!", token.line) inc = 1 if token.type_ == TokenType.OPEN_PAREN: expr, inc = parseExpression(token, prev, tokens[idx+1:]) args.append(expr) elif token.type_ in (TokenType.STRING, TokenType.TRUE, TokenType.FALSE, TokenType.INT, TokenType.FLOAT): expr, inc = parseLiteral(token, prev, tokens[idx+1:]) args.append(expr) elif token.type_ == TokenType.COLON: expr, inc = parseType(token, prev, tokens[idx+1:]) args.append(expr) elif token.type_ == TokenType.DEF: expr, inc = parseDef(token, prev, tokens[idx+1:]) args.append(expr) elif token.type_ in (TokenType.LAMBDA, TokenType.FUNC): expr, inc = parseLambda(token, prev, tokens[idx+1:]) args.append(expr) else: expr, inc = parseSymbol(token, prev, tokens[idx+1:]) args.append(expr) idx += inc prev = token return Expr(args), idx + 2 # parens def parseSymbol(token, prev, tokens): if token.type_ == TokenType.APOSTROPHE: if len(tokens) == 0 or tokens[0].type_ != TokenType.SYMBOL: raise ParseError("quote must be followed by a symbol", token.line) return Symbol(tokens[0].text, tokens[0].line, True), 2 else: return Symbol(token.text, token.line), 1 def parseLiteral(token, prev, tokens): if token.type_ == TokenType.STRING: return String(token.value), 1 elif token.type_ == TokenType.INT: return Int(token.value), 1 elif token.type_ == TokenType.FLOAT: return Float(token.value), 1 elif token.type_ in (TokenType.TRUE, TokenType.FALSE): return Bool(token.value), 1 else: return Literal(token.value), 1 def parseType(token, prev, tokens): # if the next token is a symbol, combine for a type if len(tokens) > 0 and tokens[0].type_ == TokenType.SYMBOL: return Type(f":{tokens[0].text}"), 2 elif tokens[0].type_ == TokenType.OPEN_BRACKET: # only format currently supported: # [ ] if tokens[1].type_ != TokenType.COLON: raise ParseError("invalid type definition (expecting colon)", tokens[1].line) typ, counter = parseType(tokens[1], tokens[0], tokens[2:]) if tokens[1+counter].type_ != TokenType.CLOSE_BRACKET: raise ParseError("invalid type definition (expecting close bracket)", tokens[1+counter].line) return Type(f":[]", typ), counter + 3 elif tokens[0].type_ == TokenType.OPEN_BRACE: # only format currently supported: # [ ] if tokens[1].type_ != TokenType.COLON: raise ParseError("invalid type definition (expecting colon)", tokens[1].line) typ, counter = parseType(tokens[1], tokens[0], tokens[2:]) if tokens[1+counter].type_ != TokenType.CLOSE_BRACE: raise ParseError("invalid type definition (expecting close brace)", tokens[1+counter].line) return Type(":{}", typ), counter + 3 else: raise ParseError("invalid type definition!", tokens[0].line) def parse(tokens): idx = 0 prev = None exprs = [] while tokens[idx].type_ != TokenType.EOF: token = tokens[idx] counter = 1 if token.type_ == TokenType.CLOSE_PAREN: raise ParseError("uneven parens: too many closing!", token.line) elif token.type_ == TokenType.OPEN_PAREN: expr, counter = parseExpression(token, prev, tokens[idx+1:]) exprs.append(expr) elif token.type_ in (TokenType.FALSE, TokenType.TRUE, TokenType.STRING, TokenType.INT, TokenType.FLOAT): lit, counter = parseLiteral(token, prev, tokens[idx+1:]) exprs.append(lit) elif token.type_ == TokenType.COLON: typ, counter = parseType(token, prev, tokens[idx+1:]) exprs.append(typ) else: sym, counter = parseSymbol(token, prev, tokens[idx+1:]) exprs.append(sym) idx += counter prev = token return exprs