forked from PuqiAR/Fig-TreeWalker
support function literal, set builtins to global context. great!
This commit is contained in:
19
src/Value/function.cpp
Normal file
19
src/Value/function.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <value.hpp>
|
||||
#include <Value/function.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
FunctionStruct::FunctionStruct(std::function<Value(const std::vector<Value> &)> fn,
|
||||
int argc) :
|
||||
id(nextId()),
|
||||
isBuiltin(true),
|
||||
builtin(std::move(fn)),
|
||||
builtinParamCount(argc) {}
|
||||
|
||||
Function::Function(std::function<Value(const std::vector<Value> &)> fn,
|
||||
int argc) :
|
||||
__ValueWrapper(ValueType::Function)
|
||||
{
|
||||
data = std::make_unique<FunctionStruct>(std::move(fn), argc);
|
||||
}
|
||||
}; // namespace Fig
|
||||
@@ -62,6 +62,118 @@ namespace Fig
|
||||
}
|
||||
}
|
||||
|
||||
Value Evaluator::evalFunctionCall(const Function &fn, const Ast::FunctionArguments &fnArgs, FString fnName)
|
||||
{
|
||||
FunctionStruct fnStruct = fn.getValue();
|
||||
Ast::FunctionCallArgs evaluatedArgs;
|
||||
if (fnStruct.isBuiltin)
|
||||
{
|
||||
for (const auto &argExpr : fnArgs.argv)
|
||||
{
|
||||
evaluatedArgs.argv.push_back(eval(argExpr));
|
||||
}
|
||||
if (fnStruct.builtinParamCount != -1 && fnStruct.builtinParamCount != evaluatedArgs.getLength())
|
||||
{
|
||||
static constexpr char BuiltinArgumentMismatchErrorName[] = "BuiltinArgumentMismatchError";
|
||||
throw EvaluatorError<BuiltinArgumentMismatchErrorName>(FStringView(std::format("Builtin function '{}' expects {} arguments, but {} were provided", fnName.toBasicString(), fnStruct.builtinParamCount, evaluatedArgs.getLength())), currentAddressInfo);
|
||||
}
|
||||
return fnStruct.builtin(evaluatedArgs.argv);
|
||||
}
|
||||
|
||||
// check argument, all types of parameters
|
||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
||||
if (fnArgs.getLength() < fnParas.posParas.size() || fnArgs.getLength() > fnParas.size())
|
||||
{
|
||||
static constexpr char ArgumentMismatchErrorName[] = "ArgumentMismatchError";
|
||||
throw EvaluatorError<ArgumentMismatchErrorName>(FStringView(std::format("Function '{}' expects {} to {} arguments, but {} were provided", fnName.toBasicString(), fnParas.posParas.size(), fnParas.size(), fnArgs.getLength())), currentAddressInfo);
|
||||
}
|
||||
|
||||
// positional parameters type check
|
||||
size_t i;
|
||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
||||
{
|
||||
TypeInfo expectedType(fnParas.posParas[i].second); // look up type info, if exists a type with the name, use it, else throw
|
||||
Value argVal = eval(fnArgs.argv[i]);
|
||||
TypeInfo actualType = argVal.getTypeInfo();
|
||||
if (expectedType != actualType and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError";
|
||||
throw EvaluatorError<ArgumentTypeMismatchErrorName>(FStringView(std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'", fnName.toBasicString(), fnParas.posParas[i].first.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
evaluatedArgs.argv.push_back(argVal);
|
||||
}
|
||||
// default parameters type check
|
||||
for (; i < fnArgs.getLength(); i++)
|
||||
{
|
||||
size_t defParamIndex = i - fnParas.posParas.size();
|
||||
TypeInfo expectedType = fnParas.defParas[defParamIndex].second.first;
|
||||
|
||||
Value defaultVal = eval(fnParas.defParas[defParamIndex].second.second);
|
||||
if (expectedType != defaultVal.getTypeInfo() and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char DefaultParameterTypeErrorName[] = "DefaultParameterTypeError";
|
||||
throw EvaluatorError<DefaultParameterTypeErrorName>(FStringView(std::format("In function '{}', default parameter '{}' has type '{}', which does not match the expected type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), defaultVal.getTypeInfo().toString().toBasicString(), expectedType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
|
||||
Value argVal = eval(fnArgs.argv[i]);
|
||||
TypeInfo actualType = argVal.getTypeInfo();
|
||||
if (expectedType != actualType and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError";
|
||||
throw EvaluatorError<ArgumentTypeMismatchErrorName>(FStringView(std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
evaluatedArgs.argv.push_back(argVal);
|
||||
}
|
||||
// default parameters filling
|
||||
for (; i < fnParas.size(); i++)
|
||||
{
|
||||
size_t defParamIndex = i - fnParas.posParas.size();
|
||||
Value defaultVal = eval(fnParas.defParas[defParamIndex].second.second);
|
||||
evaluatedArgs.argv.push_back(defaultVal);
|
||||
}
|
||||
// create new context for function call
|
||||
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())), currentContext);
|
||||
auto previousContext = currentContext;
|
||||
currentContext = newContext;
|
||||
// define parameters in new context
|
||||
for (size_t j = 0; j < fnParas.size(); j++)
|
||||
{
|
||||
FString paramName;
|
||||
TypeInfo paramType;
|
||||
if (j < fnParas.posParas.size())
|
||||
{
|
||||
paramName = fnParas.posParas[j].first;
|
||||
paramType = fnParas.posParas[j].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t defParamIndex = j - fnParas.posParas.size();
|
||||
paramName = fnParas.defParas[defParamIndex].first;
|
||||
paramType = fnParas.defParas[defParamIndex].second.first;
|
||||
}
|
||||
AccessModifier argAm = AccessModifier::Const;
|
||||
currentContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
||||
}
|
||||
// execute function body
|
||||
Value retVal = Value::getNullInstance();
|
||||
for (const auto &stmt : fnStruct.body->stmts)
|
||||
{
|
||||
StatementResult sr = evalStatement(stmt);
|
||||
if (sr.shouldReturn())
|
||||
{
|
||||
retVal = sr.result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentContext = previousContext;
|
||||
if (fnStruct.retType != retVal.getTypeInfo() and fnStruct.retType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ReturnTypeMismatchErrorName[] = "ReturnTypeMismatchError";
|
||||
throw EvaluatorError<ReturnTypeMismatchErrorName>(FStringView(std::format("Function '{}' expects return type '{}', but got type '{}'", fnName.toBasicString(), fnStruct.retType.toString().toBasicString(), retVal.getTypeInfo().toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
Value Evaluator::eval(Ast::Expression exp)
|
||||
{
|
||||
using Fig::Ast::AstType;
|
||||
@@ -78,7 +190,8 @@ namespace Fig
|
||||
{
|
||||
return val.value();
|
||||
}
|
||||
throw RuntimeError(FStringView(std::format("Variable '{}' not defined", varExp->name.toBasicString())));
|
||||
static constexpr char UndefinedVariableErrorName[] = "UndefinedVariableError";
|
||||
throw EvaluatorError<UndefinedVariableErrorName>(FStringView(std::format("Variable '{}' is not defined in the current scope", varExp->name.toBasicString())), varExp->getAAI());
|
||||
}
|
||||
case AstType::BinaryExpr: {
|
||||
auto binExp = std::dynamic_pointer_cast<Ast::BinaryExprAst>(exp);
|
||||
@@ -89,132 +202,54 @@ namespace Fig
|
||||
return evalUnary(unExp);
|
||||
}
|
||||
case AstType::FunctionCall: {
|
||||
// std::cerr << "Eval: function call...\n";
|
||||
auto fnCall = std::dynamic_pointer_cast<Ast::FunctionCallExpr>(exp);
|
||||
FString fnName = fnCall->name;
|
||||
if (Builtins::isBuiltinFunction(fnName))
|
||||
{
|
||||
std::vector<Value> callArgs;
|
||||
if (fnCall->arg.getLength() != Builtins::getBuiltinFunctionParamCount(fnName) and Builtins::getBuiltinFunctionParamCount(fnName) != -1) // -1 means variadic
|
||||
{
|
||||
static constexpr char BuiltinArgumentMismatchErrorName[] = "BuiltinArgumentMismatchError";
|
||||
throw EvaluatorError<BuiltinArgumentMismatchErrorName>(FStringView(std::format("Builtin function '{}' expects {} arguments, but {} were provided", fnName.toBasicString(), Builtins::getBuiltinFunctionParamCount(fnName), callArgs.size())), currentAddressInfo);
|
||||
}
|
||||
for (const auto &argExp : fnCall->arg.argv)
|
||||
{
|
||||
callArgs.push_back(eval(argExp));
|
||||
}
|
||||
return Builtins::getBuiltinFunction(fnName)(callArgs);
|
||||
}
|
||||
|
||||
auto fnValOpt = currentContext->get(fnName);
|
||||
if (!fnValOpt.has_value())
|
||||
{
|
||||
static constexpr char FunctionNotFoundErrorName[] = "FunctionNotFoundError";
|
||||
throw EvaluatorError<FunctionNotFoundErrorName>(FStringView(std::format("Function '{}' not defined", fnName.toBasicString())), currentAddressInfo);
|
||||
}
|
||||
Value fnVal = fnValOpt.value();
|
||||
if (!fnVal.is<Function>())
|
||||
Value calleeVal = eval(fnCall->callee);
|
||||
|
||||
if (!calleeVal.is<Function>())
|
||||
{
|
||||
static constexpr char NotAFunctionErrorName[] = "NotAFunctionError";
|
||||
throw EvaluatorError<NotAFunctionErrorName>(FStringView(std::format("'{}' is not a function or callable", fnName.toBasicString())), currentAddressInfo);
|
||||
}
|
||||
FunctionStruct fnStruct = fnVal.as<Function>().getValue();
|
||||
// check argument, all types of parameters
|
||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
||||
Ast::FunctionArguments fnArgs = fnCall->arg;
|
||||
if (fnArgs.getLength() < fnParas.posParas.size() || fnArgs.getLength() > fnParas.size())
|
||||
{
|
||||
static constexpr char ArgumentMismatchErrorName[] = "ArgumentMismatchError";
|
||||
throw EvaluatorError<ArgumentMismatchErrorName>(FStringView(std::format("Function '{}' expects {} to {} arguments, but {} were provided", fnName.toBasicString(), fnParas.posParas.size(), fnParas.size(), fnArgs.getLength())), currentAddressInfo);
|
||||
throw EvaluatorError<NotAFunctionErrorName>(
|
||||
FStringView(std::format(
|
||||
"'{}' is not a function or callable",
|
||||
calleeVal.toString().toBasicString())),
|
||||
currentAddressInfo);
|
||||
}
|
||||
|
||||
Ast::FunctionCallArgs evaluatedArgs;
|
||||
Function fn = calleeVal.as<Function>();
|
||||
|
||||
// positional parameters type check
|
||||
size_t i;
|
||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
||||
{
|
||||
TypeInfo expectedType(fnParas.posParas[i].second); // look up type info, if exists a type with the name, use it, else throw
|
||||
Value argVal = eval(fnArgs.argv[i]);
|
||||
TypeInfo actualType = argVal.getTypeInfo();
|
||||
if (expectedType != actualType and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError";
|
||||
throw EvaluatorError<ArgumentTypeMismatchErrorName>(FStringView(std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'", fnName.toBasicString(), fnParas.posParas[i].first.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
evaluatedArgs.argv.push_back(argVal);
|
||||
}
|
||||
// default parameters type check
|
||||
for (; i < fnArgs.getLength(); i++)
|
||||
{
|
||||
size_t defParamIndex = i - fnParas.posParas.size();
|
||||
TypeInfo expectedType = fnParas.defParas[defParamIndex].second.first;
|
||||
FString fnName = u8"<anonymous>";
|
||||
if (auto var = std::dynamic_pointer_cast<Ast::VarExprAst>(fnCall->callee))
|
||||
fnName = var->name; // try to get function name
|
||||
|
||||
Value defaultVal = eval(fnParas.defParas[defParamIndex].second.second);
|
||||
if (expectedType != defaultVal.getTypeInfo() and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char DefaultParameterTypeErrorName[] = "DefaultParameterTypeError";
|
||||
throw EvaluatorError<DefaultParameterTypeErrorName>(FStringView(std::format("In function '{}', default parameter '{}' has type '{}', which does not match the expected type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), defaultVal.getTypeInfo().toString().toBasicString(), expectedType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
return evalFunctionCall(fn, fnCall->arg, fnName);
|
||||
}
|
||||
|
||||
Value argVal = eval(fnArgs.argv[i]);
|
||||
TypeInfo actualType = argVal.getTypeInfo();
|
||||
if (expectedType != actualType and expectedType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError";
|
||||
throw EvaluatorError<ArgumentTypeMismatchErrorName>(FStringView(std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
evaluatedArgs.argv.push_back(argVal);
|
||||
}
|
||||
// default parameters filling
|
||||
for (; i < fnParas.size(); i++)
|
||||
case AstType::FunctionLiteralExpr: {
|
||||
auto fn = std::dynamic_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
||||
|
||||
if (fn->isExprMode())
|
||||
{
|
||||
size_t defParamIndex = i - fnParas.posParas.size();
|
||||
Value defaultVal = eval(fnParas.defParas[defParamIndex].second.second);
|
||||
evaluatedArgs.argv.push_back(defaultVal);
|
||||
Ast::BlockStatement body = std::make_shared<Ast::BlockStatementAst>();
|
||||
body->setAAI(fn->getExprBody()->getAAI());
|
||||
Ast::Statement retSt = std::make_shared<Ast::ReturnSt>(fn->getExprBody());
|
||||
retSt->setAAI(fn->getExprBody()->getAAI());
|
||||
body->stmts.push_back(retSt);
|
||||
return Function(
|
||||
fn->paras,
|
||||
ValueType::Any,
|
||||
body
|
||||
);
|
||||
}
|
||||
// create new context for function call
|
||||
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())), currentContext);
|
||||
auto previousContext = currentContext;
|
||||
currentContext = newContext;
|
||||
// define parameters in new context
|
||||
for (size_t j = 0; j < fnParas.size(); j++)
|
||||
else
|
||||
{
|
||||
FString paramName;
|
||||
TypeInfo paramType;
|
||||
if (j < fnParas.posParas.size())
|
||||
{
|
||||
paramName = fnParas.posParas[j].first;
|
||||
paramType = fnParas.posParas[j].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t defParamIndex = j - fnParas.posParas.size();
|
||||
paramName = fnParas.defParas[defParamIndex].first;
|
||||
paramType = fnParas.defParas[defParamIndex].second.first;
|
||||
}
|
||||
AccessModifier argAm = AccessModifier::Const;
|
||||
currentContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
|
||||
Ast::BlockStatement body = fn->getBlockBody();
|
||||
return Function(
|
||||
fn->paras,
|
||||
ValueType::Any,
|
||||
body
|
||||
);
|
||||
}
|
||||
// execute function body
|
||||
Value retVal = Value::getNullInstance();
|
||||
for (const auto &stmt : fnStruct.body->stmts)
|
||||
{
|
||||
StatementResult sr = evalStatement(stmt);
|
||||
if (sr.shouldReturn())
|
||||
{
|
||||
retVal = sr.result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentContext = previousContext;
|
||||
if (fnStruct.retType != retVal.getTypeInfo() and fnStruct.retType != ValueType::Any)
|
||||
{
|
||||
static constexpr char ReturnTypeMismatchErrorName[] = "ReturnTypeMismatchError";
|
||||
throw EvaluatorError<ReturnTypeMismatchErrorName>(FStringView(std::format("Function '{}' expects return type '{}', but got type '{}'", fnName.toBasicString(), fnStruct.retType.toString().toBasicString(), retVal.getTypeInfo().toString().toBasicString())), currentAddressInfo);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
case AstType::ListExpr: {
|
||||
auto listexpr = std::dynamic_pointer_cast<Ast::ListExprAst>(exp);
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Fig
|
||||
{FString(u8":="), TokenType::Walrus},
|
||||
{FString(u8"**"), TokenType::Power},
|
||||
{FString(u8"->"), TokenType::RightArrow},
|
||||
{FString(u8"=>"), TokenType::DoubleArrow},
|
||||
|
||||
// 单字符
|
||||
{FString(u8"+"), TokenType::Plus},
|
||||
@@ -62,7 +63,7 @@ namespace Fig
|
||||
{FString(u8"or"), TokenType::Or},
|
||||
{FString(u8"not"), TokenType::Not},
|
||||
{FString(u8"import"), TokenType::Import},
|
||||
{FString(u8"fun"), TokenType::Function},
|
||||
{FString(u8"func"), TokenType::Function},
|
||||
{FString(u8"var"), TokenType::Variable},
|
||||
{FString(u8"const"), TokenType::Const},
|
||||
{FString(u8"final"), TokenType::Final},
|
||||
|
||||
128
src/parser.cpp
128
src/parser.cpp
@@ -361,20 +361,17 @@ namespace Fig
|
||||
{
|
||||
// stmt = __parseVarDef();
|
||||
// expect(TokenType::Semicolon);
|
||||
// next();
|
||||
if (isNext(TokenType::Variable) || isNext(TokenType::Const))
|
||||
next(); // consume `public`
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
next(); // consume `public`
|
||||
stmt = __parseVarDef(true);
|
||||
}
|
||||
else if (isNext(TokenType::Function))
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next(); // consume `public`
|
||||
expectPeek(TokenType::Identifier);
|
||||
next();
|
||||
stmt = __parseFunctionDef(true);
|
||||
}
|
||||
else if (isNext(TokenType::Struct))
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
stmt = __parseStructDef(true);
|
||||
}
|
||||
@@ -387,9 +384,8 @@ namespace Fig
|
||||
{
|
||||
stmt = __parseVarDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Function))
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
expectPeek(TokenType::Identifier, u8"function name");
|
||||
next();
|
||||
stmt = __parseFunctionDef(false);
|
||||
}
|
||||
@@ -523,55 +519,11 @@ namespace Fig
|
||||
return makeAst<Ast::ReturnSt>(retValue);
|
||||
}
|
||||
|
||||
Ast::FunctionCall Parser::__parseFunctionCall(FString funcName)
|
||||
{
|
||||
// entry: current at '('
|
||||
next(); // consume '('
|
||||
std::vector<Ast::Expression> args;
|
||||
if (!isThis(TokenType::RightParen))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
args.push_back(parseExpression(0, TokenType::Comma, TokenType::RightParen));
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // consume ','
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightParen);
|
||||
next(); // consume ')'
|
||||
return makeAst<Ast::FunctionCallExpr>(funcName, Ast::FunctionArguments(args));
|
||||
}
|
||||
|
||||
Ast::VarExpr Parser::__parseVarExpr(FString name)
|
||||
{
|
||||
return makeAst<Ast::VarExprAst>(name);
|
||||
}
|
||||
|
||||
Ast::LambdaExpr Parser::__parseLambdaExpr()
|
||||
{
|
||||
// entry: current tok Token::LeftParen and last is Token::Function
|
||||
/*
|
||||
Lambda in Fig like:
|
||||
fun (params) -> <return type> {...}
|
||||
*/
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
// if OK, the current token is `)` next one
|
||||
FString tiName = ValueType::Any.name;
|
||||
if (isThis(TokenType::RightArrow)) // ->
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier);
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
}
|
||||
expect(TokenType::LeftBrace); // `{`
|
||||
return makeAst<Ast::LambdaExprAst>(params, tiName, __parseBlockStatement());
|
||||
}
|
||||
|
||||
Ast::UnaryExpr Parser::__parsePrefix(Ast::Operator op, Precedence bp)
|
||||
{
|
||||
return makeAst<Ast::UnaryExprAst>(op, parseExpression(bp));
|
||||
@@ -581,6 +533,32 @@ namespace Fig
|
||||
return makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp));
|
||||
}
|
||||
|
||||
Ast::Expression Parser::__parseCall(Ast::Expression callee)
|
||||
{
|
||||
next(); // consume '('
|
||||
std::vector<Ast::Expression> args;
|
||||
|
||||
if (!isThis(TokenType::RightParen))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
args.push_back(parseExpression(0, TokenType::Comma, TokenType::RightParen));
|
||||
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expect(TokenType::RightParen);
|
||||
next(); // consume ')'
|
||||
|
||||
return makeAst<Ast::FunctionCallExpr>(callee, Ast::FunctionArguments(args));
|
||||
}
|
||||
|
||||
Ast::ListExpr Parser::__parseListExpr()
|
||||
{
|
||||
// entry: current is `[`
|
||||
@@ -739,6 +717,27 @@ namespace Fig
|
||||
}
|
||||
return nullptr; // to suppress compiler warning
|
||||
}
|
||||
|
||||
Ast::FunctionLiteralExpr Parser::__parseFunctionLiteralExpr()
|
||||
{
|
||||
// entry: current is Token::LeftParen and last is Token::Function
|
||||
/*
|
||||
Function literal:
|
||||
func (params){...}
|
||||
or
|
||||
func (params) => <expression>
|
||||
*/
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
if (isThis(TokenType::DoubleArrow)) // =>
|
||||
{
|
||||
next();
|
||||
Ast::Expression bodyExpr = parseExpression(0);
|
||||
return makeAst<Ast::FunctionLiteralExprAst>(params, bodyExpr);
|
||||
}
|
||||
expect(TokenType::LeftBrace); // `{`
|
||||
return makeAst<Ast::FunctionLiteralExprAst>(params, __parseBlockStatement());
|
||||
}
|
||||
|
||||
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
|
||||
{
|
||||
Ast::Expression lhs;
|
||||
@@ -764,6 +763,17 @@ namespace Fig
|
||||
{
|
||||
lhs = __parseMapExpr(); // auto consume
|
||||
}
|
||||
else if (tok.getType() == TokenType::Function)
|
||||
{
|
||||
next(); // consume `function`
|
||||
if (currentToken().getType() == TokenType::Identifier)
|
||||
{
|
||||
// err
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Function literal should not have a name"));
|
||||
}
|
||||
expect(TokenType::LeftParen);
|
||||
lhs = __parseFunctionLiteralExpr();
|
||||
}
|
||||
else if (tok.isLiteral())
|
||||
{
|
||||
lhs = __parseValueExpr();
|
||||
@@ -773,11 +783,7 @@ namespace Fig
|
||||
{
|
||||
FString id = tok.getValue();
|
||||
next();
|
||||
if (currentToken().getType() == TokenType::LeftParen)
|
||||
{
|
||||
lhs = __parseFunctionCall(id); // foo(...)
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LeftBrace)
|
||||
if (currentToken().getType() == TokenType::LeftBrace)
|
||||
{
|
||||
lhs = __parseInitExpr(id); // a_struct{init...}
|
||||
}
|
||||
@@ -803,6 +809,12 @@ namespace Fig
|
||||
tok = currentToken();
|
||||
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break;
|
||||
|
||||
if (tok.getType() == TokenType::LeftParen)
|
||||
{
|
||||
lhs = __parseCall(lhs);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ternary
|
||||
if (tok.getType() == TokenType::Question)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user