support function literal, set builtins to global context. great!
This commit is contained in:
@@ -1,248 +0,0 @@
|
||||
## `Fig Programming Language` <font face="Consolas"> DESIGN DOC </font>
|
||||
|
||||
---
|
||||
### 关键词解释 Token
|
||||
|
||||
``` cpp
|
||||
enum class TokenType : int8_t
|
||||
{
|
||||
Illegal = -1,
|
||||
EndOfFile = 0,
|
||||
|
||||
Comments,
|
||||
|
||||
Identifier,
|
||||
|
||||
/* Keywords */
|
||||
And, // and
|
||||
Or, // or
|
||||
Not, // not
|
||||
Import, // import
|
||||
Function, // fun
|
||||
Variable, // var
|
||||
Const, // const
|
||||
Final, // final
|
||||
While, // while
|
||||
For, // for
|
||||
Struct, // struct
|
||||
Interface, // interface
|
||||
Implement, // implement
|
||||
Public, // public
|
||||
|
||||
// TypeNull, // Null
|
||||
// TypeInt, // Int
|
||||
// TypeString, // String
|
||||
// TypeBool, // Bool
|
||||
// TypeDouble, // Double
|
||||
|
||||
/* Literal Types (not keyword)*/
|
||||
LiteralNumber, // number (int,float...)
|
||||
LiteralString, // FString
|
||||
LiteralBool, // bool (true/false)
|
||||
LiteralNull, // null (Null的唯一实例)
|
||||
|
||||
/* Punct */
|
||||
Plus, // +
|
||||
Minus, // -
|
||||
Asterisk, // *
|
||||
Slash, // /
|
||||
Percent, // %
|
||||
Caret, // ^
|
||||
Ampersand, // &
|
||||
Pipe, // |
|
||||
Tilde, // ~
|
||||
ShiftLeft, // <<
|
||||
ShiftRight, // >>
|
||||
// Exclamation, // !
|
||||
Question, // ?
|
||||
Assign, // =
|
||||
Less, // <
|
||||
Greater, // >
|
||||
Dot, // .
|
||||
Comma, // ,
|
||||
Colon, // :
|
||||
Semicolon, // ;
|
||||
SingleQuote, // '
|
||||
DoubleQuote, // "
|
||||
// Backtick, // `
|
||||
// At, // @
|
||||
// Hash, // #
|
||||
// Dollar, // $
|
||||
// Backslash, // '\'
|
||||
// Underscore, // _
|
||||
LeftParen, // (
|
||||
RightParen, // )
|
||||
LeftBracket, // [
|
||||
RightBracket, // ]
|
||||
LeftBrace, // {
|
||||
RightBrace, // }
|
||||
// LeftArrow, // <-
|
||||
RightArrow, // ->
|
||||
// DoubleArrow, // =>
|
||||
Equal, // ==
|
||||
NotEqual, // !=
|
||||
LessEqual, // <=
|
||||
GreaterEqual, // >=
|
||||
PlusEqual, // +=
|
||||
MinusEqual, // -=
|
||||
AsteriskEqual, // *=
|
||||
SlashEqual, // /=
|
||||
PercentEqual, // %=
|
||||
CaretEqual, // ^=
|
||||
DoublePlus, // ++
|
||||
DoubleMinus, // --
|
||||
DoubleAmpersand, // &&
|
||||
DoublePipe, // ||
|
||||
Walrus, // :=
|
||||
Power, // **
|
||||
};
|
||||
```
|
||||
|
||||
* `Illegal`
|
||||
非法Token:无法解析或语法错误
|
||||
|
||||
* `EndOfFile`
|
||||
即:
|
||||
```cpp
|
||||
EOF
|
||||
```
|
||||
文件终止符
|
||||
|
||||
* `Comments`
|
||||
注释Token,包括单行和多行
|
||||
|
||||
* `Identifier`
|
||||
标识符,用户定义的‘名字’
|
||||
|
||||
* `And` -> `&&` 或 `and`
|
||||
逻辑与
|
||||
|
||||
* `Or` -> `||` 或 `or`
|
||||
逻辑或
|
||||
|
||||
* `Not` -> `!` 或 `!`
|
||||
逻辑非
|
||||
|
||||
* `Import` -> `import`
|
||||
导入关键字,用于导入包。 e.g
|
||||
``` python
|
||||
import std.io
|
||||
```
|
||||
|
||||
* `Function` -> `function`
|
||||
定义函数,匿名也可
|
||||
``` javascript
|
||||
function greeting() -> Null public
|
||||
{
|
||||
std.io.println("Hello, world!");
|
||||
}
|
||||
|
||||
function intAdder() -> Function public
|
||||
{
|
||||
return function(n1: Int, n2: Int) => n1 + n2;
|
||||
}
|
||||
```
|
||||
此处的 `public` 为公开标识
|
||||
不进行显示声明 `public` 默认为私有,即对象仅能在当前作用域访问
|
||||
|
||||
* `Variable` -> `var`
|
||||
定义变量
|
||||
``` dart
|
||||
var foobar;
|
||||
var defaultVal = 1145;
|
||||
var numberSpecific: Int;
|
||||
var numberDefault: Int = 91;
|
||||
|
||||
foobar = "hello, world!";
|
||||
foobar = 13;
|
||||
|
||||
defaultVal = "it can be any value";
|
||||
|
||||
numberSpecific = 78;
|
||||
numberDefault = 0;
|
||||
```
|
||||
|
||||
* `Const` -> `const`
|
||||
定义`全过程`常量: 从词法分析到求值器内的生命周期都为常量,仅能**在生命周期内**赋值一次,使用时也只有一个唯一对象
|
||||
|
||||
必须在源码中指定值
|
||||
|
||||
``` dart
|
||||
const Pi = 3.1415926; // recommended
|
||||
|
||||
const name; // ❌ 错误
|
||||
```
|
||||
|
||||
定义后的常量,其值及类型均不可改变,故可省略类型标识。这是推荐的写法
|
||||
同时,也可作为结构体成员的修饰
|
||||
``` cpp
|
||||
struct MathConstants
|
||||
{
|
||||
const Pi = 3.1415926;
|
||||
};
|
||||
```
|
||||
|
||||
* `Final` -> `final`
|
||||
定义`结构体运行时`常量:从运行期开始的常量,仅能**在运行时**被赋值一次, **仅修饰结构体成员**
|
||||
不存在 **final** 类型的外部常量
|
||||
|
||||
定义后的常量,其值及类型均不可改变,故可省略类型标识。这是推荐的写法
|
||||
``` cpp
|
||||
struct Person
|
||||
{
|
||||
final name: String
|
||||
final age: Int
|
||||
|
||||
final sex: String = "gender" // ❌ 请使用 const 代替
|
||||
}
|
||||
```
|
||||
|
||||
* `While` -> `while`
|
||||
while循环,满足一个布尔类型条件循环执行语句
|
||||
|
||||
``` cpp
|
||||
while (ans != 27.19236)
|
||||
{
|
||||
ans = Int.parse(std.io.readline());
|
||||
}
|
||||
```
|
||||
|
||||
* `For` -> `for`
|
||||
for循环,拥有初始语句、条件、增长语句
|
||||
``` cpp
|
||||
for (init; condition; increment)
|
||||
{
|
||||
statements...;
|
||||
}
|
||||
```
|
||||
|
||||
* `Struct` -> `struct`
|
||||
结构体,面对对象
|
||||
|
||||
``` cpp
|
||||
struct Person
|
||||
{
|
||||
public final name: String; // public, final
|
||||
public age: Int; // public
|
||||
sex: String; // private normally;
|
||||
|
||||
const ADULT_AGE = 18; // private, const
|
||||
|
||||
fun printInfo()
|
||||
{
|
||||
std.io.println("name: {}, age: {}, sex: {}", name, age, sex);
|
||||
}
|
||||
};
|
||||
|
||||
var person = Person {"Fig", 1, "IDK"};
|
||||
// or
|
||||
var person = Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered
|
||||
|
||||
var name = "Fig";
|
||||
var age = 1;
|
||||
var sex = "IDK";
|
||||
|
||||
var person = Person {name, age, sex};
|
||||
// = `var person = Person {name: name, age: age, sex: sex}`
|
||||
```
|
||||
|
||||
2
function.py
Normal file
2
function.py
Normal file
@@ -0,0 +1,2 @@
|
||||
print = 123
|
||||
print()
|
||||
@@ -21,7 +21,7 @@ namespace Fig::Ast
|
||||
class FunctionCallExpr final : public ExpressionAst
|
||||
{
|
||||
public:
|
||||
FString name;
|
||||
Expression callee; // 不是 name 了!!
|
||||
FunctionArguments arg;
|
||||
|
||||
FunctionCallExpr()
|
||||
@@ -29,15 +29,15 @@ namespace Fig::Ast
|
||||
type = AstType::FunctionCall;
|
||||
}
|
||||
|
||||
FunctionCallExpr(FString _name, FunctionArguments _arg) :
|
||||
name(std::move(_name)), arg(std::move(_arg))
|
||||
FunctionCallExpr(Expression _callee, FunctionArguments _arg) :
|
||||
callee(std::move(_callee)), arg(std::move(_arg))
|
||||
{
|
||||
type = AstType::FunctionCall;
|
||||
}
|
||||
|
||||
virtual FString toString() override
|
||||
virtual FString toString() override
|
||||
{
|
||||
FString s = name;
|
||||
FString s = callee->toString();
|
||||
s += u8"(";
|
||||
for (size_t i = 0; i < arg.argv.size(); ++i)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace Fig::Ast
|
||||
{
|
||||
/*
|
||||
fun greet(greeting, name:String, age:Int, split:String=":") public -> Null
|
||||
func greet(greeting, name:String, age:Int, split:String=":") -> Null
|
||||
{
|
||||
io.println("{}, {}{}{}", greeting, name, split, age);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Fig::Ast
|
||||
`split` -> default parameter
|
||||
*/
|
||||
|
||||
class FunctionDefSt final : public StatementAst // for define
|
||||
class FunctionDefSt final : public StatementAst // for definition
|
||||
{
|
||||
public:
|
||||
FString name;
|
||||
|
||||
47
include/Ast/FunctionLiteralExpr.hpp
Normal file
47
include/Ast/FunctionLiteralExpr.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <fig_string.hpp>
|
||||
#include <variant>
|
||||
|
||||
namespace Fig::Ast
|
||||
{
|
||||
class FunctionLiteralExprAst final : public ExpressionAst
|
||||
{
|
||||
public:
|
||||
FunctionParameters paras;
|
||||
std::variant<BlockStatement, Expression> body;
|
||||
|
||||
FunctionLiteralExprAst(FunctionParameters _paras, BlockStatement _body) :
|
||||
paras(std::move(_paras)), body(std::move(_body))
|
||||
{
|
||||
type = AstType::FunctionLiteralExpr;
|
||||
}
|
||||
|
||||
FunctionLiteralExprAst(FunctionParameters _paras, Expression _exprBody) :
|
||||
paras(std::move(_paras)), body(std::move(_exprBody))
|
||||
{
|
||||
type = AstType::FunctionLiteralExpr;
|
||||
}
|
||||
|
||||
bool isExprMode() const
|
||||
{
|
||||
return std::holds_alternative<Expression>(body);
|
||||
}
|
||||
|
||||
BlockStatement &getBlockBody()
|
||||
{
|
||||
return std::get<BlockStatement>(body);
|
||||
}
|
||||
|
||||
Expression &getExprBody()
|
||||
{
|
||||
return std::get<Expression>(body);
|
||||
}
|
||||
|
||||
~FunctionLiteralExprAst() = default;
|
||||
};
|
||||
|
||||
using FunctionLiteralExpr = std::shared_ptr<FunctionLiteralExprAst>;
|
||||
} // namespace Fig::Ast
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
|
||||
#include <Value/Type.hpp>
|
||||
#include <fig_string.hpp>
|
||||
|
||||
namespace Fig::Ast
|
||||
{
|
||||
class LambdaExprAst : public ExpressionAst
|
||||
{
|
||||
public:
|
||||
/*
|
||||
Lambda:
|
||||
fun (greeting) -> Null {}
|
||||
*/
|
||||
|
||||
FunctionParameters paras;
|
||||
FString retType;
|
||||
BlockStatement body;
|
||||
LambdaExprAst() :
|
||||
retType(ValueType::Null.name)
|
||||
{
|
||||
type = AstType::LambdaExpr;
|
||||
}
|
||||
LambdaExprAst(FunctionParameters _paras, FString _retType, BlockStatement _body) :
|
||||
retType(ValueType::Null.name)
|
||||
{
|
||||
paras = std::move(_paras);
|
||||
retType = std::move(_retType);
|
||||
body = std::move(_body);
|
||||
}
|
||||
|
||||
virtual FString typeName() override
|
||||
{
|
||||
return FString(std::format("LambdaExprAst<{}>", retType.toBasicString()));
|
||||
}
|
||||
virtual ~LambdaExprAst() = default;
|
||||
};
|
||||
|
||||
using LambdaExpr = std::shared_ptr<LambdaExprAst>;
|
||||
}; // namespace Fig
|
||||
@@ -30,6 +30,7 @@ namespace Fig::Ast
|
||||
TupleExpr, // ()
|
||||
MapExpr, // {}
|
||||
InitExpr, // struct{}
|
||||
FunctionLiteralExpr,
|
||||
|
||||
/* Statement */
|
||||
BlockStatement,
|
||||
@@ -312,7 +313,7 @@ namespace Fig::Ast
|
||||
class BlockStatementAst : public StatementAst
|
||||
{
|
||||
public:
|
||||
const std::vector<Statement> stmts;
|
||||
std::vector<Statement> stmts;
|
||||
BlockStatementAst()
|
||||
{
|
||||
type = AstType::BlockStatement;
|
||||
|
||||
@@ -42,9 +42,6 @@ public:
|
||||
case AstType::IfSt:
|
||||
printIfSt(std::static_pointer_cast<IfSt>(node), indent);
|
||||
break;
|
||||
case AstType::LambdaExpr:
|
||||
printLambdaExpr(std::static_pointer_cast<LambdaExprAst>(node), indent);
|
||||
break;
|
||||
case AstType::TernaryExpr:
|
||||
printTernaryExpr(std::static_pointer_cast<TernaryExprAst>(node), indent);
|
||||
break;
|
||||
@@ -147,8 +144,6 @@ private:
|
||||
printIndent(indent);
|
||||
std::cout << "FunctionCall\n";
|
||||
printIndent(indent + 2);
|
||||
std::cout << "FuncName: ";
|
||||
printFString(node->name, 0);
|
||||
printIndent(indent + 2);
|
||||
}
|
||||
|
||||
@@ -175,14 +170,6 @@ private:
|
||||
printIndent(indent + 2);
|
||||
}
|
||||
|
||||
void printLambdaExpr(const std::shared_ptr<LambdaExprAst> &node, int indent)
|
||||
{
|
||||
printIndent(indent);
|
||||
std::cout << "LambdaExpr\n"
|
||||
<< node->toString().toBasicString();
|
||||
printIndent(indent + 2);
|
||||
}
|
||||
|
||||
void printTernaryExpr(const std::shared_ptr<TernaryExprAst> &node, int indent)
|
||||
{
|
||||
printIndent(indent);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <Value/BaseValue.hpp>
|
||||
#include <Value/Type.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class Value;
|
||||
|
||||
/* complex objects */
|
||||
struct FunctionStruct
|
||||
{
|
||||
@@ -15,6 +17,10 @@ namespace Fig
|
||||
TypeInfo retType;
|
||||
Ast::BlockStatement body;
|
||||
|
||||
bool isBuiltin = false;
|
||||
std::function<Value(const std::vector<Value> &)> builtin;
|
||||
int builtinParamCount = -1;
|
||||
|
||||
FunctionStruct(Ast::FunctionParameters _paras, TypeInfo _retType, Ast::BlockStatement _body) :
|
||||
id(nextId()), // 分配唯一 ID
|
||||
paras(std::move(_paras)),
|
||||
@@ -23,8 +29,10 @@ namespace Fig
|
||||
{
|
||||
}
|
||||
|
||||
FunctionStruct(std::function<Value(const std::vector<Value> &)> fn, int argc);
|
||||
|
||||
FunctionStruct(const FunctionStruct &other) :
|
||||
id(other.id), paras(other.paras), retType(other.retType), body(other.body) {}
|
||||
id(other.id), paras(other.paras), retType(other.retType), body(other.body), isBuiltin(other.isBuiltin), builtin(other.builtin), builtinParamCount(other.builtinParamCount) {}
|
||||
|
||||
FunctionStruct &operator=(const FunctionStruct &other) = default;
|
||||
FunctionStruct(FunctionStruct &&) noexcept = default;
|
||||
@@ -61,6 +69,8 @@ namespace Fig
|
||||
data = std::make_unique<FunctionStruct>(
|
||||
std::move(paras), std::move(ret), std::move(body));
|
||||
}
|
||||
Function(std::function<Value(const std::vector<Value> &)> fn, int argc);
|
||||
|
||||
bool operator==(const Function &other) const noexcept
|
||||
{
|
||||
if (!data || !other.data) return false;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#include <Ast/FunctionCall.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Ast/FunctionDefSt.hpp>
|
||||
#include <Ast/FunctionLiteralExpr.hpp>
|
||||
#include <Ast/IfSt.hpp>
|
||||
#include <Ast/ImplementSt.hpp>
|
||||
#include <Ast/InitExpr.hpp>
|
||||
#include <Ast/LambdaExpr.hpp>
|
||||
#include <Ast/StructDefSt.hpp>
|
||||
#include <Ast/TernaryExpr.hpp>
|
||||
#include <Ast/UnaryExpr.hpp>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
|
||||
#include <builtins.hpp>
|
||||
#include <error.hpp>
|
||||
#include <fig_string.hpp>
|
||||
#include <ast.hpp>
|
||||
@@ -84,6 +82,26 @@ namespace Fig
|
||||
{
|
||||
globalContext = std::make_shared<Context>(FString(u8"global"));
|
||||
currentContext = globalContext;
|
||||
|
||||
for (auto &[name, fn] : Builtins::builtinFunctions)
|
||||
{
|
||||
int argc = Builtins::getBuiltinFunctionParamCount(name);
|
||||
Function f(fn, argc);
|
||||
globalContext->def(
|
||||
name,
|
||||
ValueType::Function,
|
||||
AccessModifier::PublicConst,
|
||||
Value(f));
|
||||
}
|
||||
|
||||
for (auto &[name, val] : Builtins::builtinValues)
|
||||
{
|
||||
globalContext->def(
|
||||
name,
|
||||
val.getTypeInfo(),
|
||||
AccessModifier::PublicConst,
|
||||
val);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Context> getCurrentContext() { return currentContext; }
|
||||
@@ -95,6 +113,8 @@ namespace Fig
|
||||
|
||||
StatementResult evalStatement(const Ast::Statement &);
|
||||
|
||||
Value evalFunctionCall(const Function &, const Ast::FunctionArguments &, FString fnName = u8"<anonymous>");
|
||||
|
||||
Value eval(Ast::Expression);
|
||||
void run();
|
||||
void printStackTrace() const;
|
||||
|
||||
@@ -174,12 +174,19 @@ namespace Fig
|
||||
return getBindingPower(op).second;
|
||||
}
|
||||
|
||||
// template <class _Tp, class... Args>
|
||||
// std::shared_ptr<_Tp> makeAst(Args &&...args)
|
||||
// {
|
||||
// _Tp node(std::forward<Args>(args)...);
|
||||
// node.setAAI(currentAAI);
|
||||
// return std::shared_ptr<_Tp>(new _Tp(node));
|
||||
// }
|
||||
template <class _Tp, class... Args>
|
||||
std::shared_ptr<_Tp> makeAst(Args &&...args)
|
||||
{
|
||||
_Tp node(args...);
|
||||
node.setAAI(currentAAI);
|
||||
return std::shared_ptr<_Tp>(new _Tp(node));
|
||||
std::shared_ptr<_Tp> ptr = std::make_shared<_Tp>(std::forward<Args>(args)...);
|
||||
ptr->setAAI(currentAAI);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type)
|
||||
@@ -236,7 +243,6 @@ namespace Fig
|
||||
Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool)
|
||||
Value __parseValue();
|
||||
Ast::ValueExpr __parseValueExpr();
|
||||
Ast::FunctionCall __parseFunctionCall(FString);
|
||||
Ast::FunctionParameters __parseFunctionParameters(); // entry: current is Token::LeftParen
|
||||
Ast::Statement __parseStatement(); // entry: (idk)
|
||||
Ast::BlockStatement __parseBlockStatement(); // entry: current is Token::LeftBrace
|
||||
@@ -246,18 +252,20 @@ namespace Fig
|
||||
Ast::Return __parseReturn(); // entry: current is Token::Return
|
||||
|
||||
Ast::VarExpr __parseVarExpr(FString);
|
||||
Ast::LambdaExpr __parseLambdaExpr();
|
||||
Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool)
|
||||
Ast::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool)
|
||||
|
||||
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
|
||||
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);
|
||||
|
||||
Ast::Expression __parseCall(Ast::Expression);
|
||||
|
||||
Ast::ListExpr __parseListExpr(); // entry: current is `[`
|
||||
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
|
||||
Ast::MapExpr __parseMapExpr(); // entry: current is `{`
|
||||
|
||||
Ast::MapExpr __parseMapExpr(); // entry: current is `{`
|
||||
Ast::InitExpr __parseInitExpr(FString); // entry: current is `{`, ahead is struct name. arg (struct name : FString)
|
||||
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
|
||||
|
||||
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
|
||||
|
||||
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
||||
std::vector<Ast::AstBase> parseAll();
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Fig
|
||||
Or, // or
|
||||
Not, // not
|
||||
Import, // import
|
||||
Function, // fun
|
||||
Function, // func
|
||||
Variable, // var
|
||||
Const, // const
|
||||
Final, // final
|
||||
@@ -85,7 +85,7 @@ namespace Fig
|
||||
RightBrace, // }
|
||||
// LeftArrow, // <-
|
||||
RightArrow, // ->
|
||||
// DoubleArrow, // =>
|
||||
DoubleArrow, // =>
|
||||
Equal, // ==
|
||||
NotEqual, // !=
|
||||
LessEqual, // <=
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
9
test.fig
9
test.fig
@@ -1 +1,8 @@
|
||||
var x = 10
|
||||
func build_adder(x) -> Function
|
||||
{
|
||||
return func(a) => a + x;
|
||||
}
|
||||
|
||||
var add2 = build_adder(2);
|
||||
var println = __fstdout_println;
|
||||
println(add2(1));
|
||||
Reference in New Issue
Block a user