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
|
class FunctionCallExpr final : public ExpressionAst
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FString name;
|
Expression callee; // 不是 name 了!!
|
||||||
FunctionArguments arg;
|
FunctionArguments arg;
|
||||||
|
|
||||||
FunctionCallExpr()
|
FunctionCallExpr()
|
||||||
@@ -29,15 +29,15 @@ namespace Fig::Ast
|
|||||||
type = AstType::FunctionCall;
|
type = AstType::FunctionCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionCallExpr(FString _name, FunctionArguments _arg) :
|
FunctionCallExpr(Expression _callee, FunctionArguments _arg) :
|
||||||
name(std::move(_name)), arg(std::move(_arg))
|
callee(std::move(_callee)), arg(std::move(_arg))
|
||||||
{
|
{
|
||||||
type = AstType::FunctionCall;
|
type = AstType::FunctionCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual FString toString() override
|
virtual FString toString() override
|
||||||
{
|
{
|
||||||
FString s = name;
|
FString s = callee->toString();
|
||||||
s += u8"(";
|
s += u8"(";
|
||||||
for (size_t i = 0; i < arg.argv.size(); ++i)
|
for (size_t i = 0; i < arg.argv.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
namespace Fig::Ast
|
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);
|
io.println("{}, {}{}{}", greeting, name, split, age);
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace Fig::Ast
|
|||||||
`split` -> default parameter
|
`split` -> default parameter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class FunctionDefSt final : public StatementAst // for define
|
class FunctionDefSt final : public StatementAst // for definition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FString name;
|
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, // ()
|
TupleExpr, // ()
|
||||||
MapExpr, // {}
|
MapExpr, // {}
|
||||||
InitExpr, // struct{}
|
InitExpr, // struct{}
|
||||||
|
FunctionLiteralExpr,
|
||||||
|
|
||||||
/* Statement */
|
/* Statement */
|
||||||
BlockStatement,
|
BlockStatement,
|
||||||
@@ -312,7 +313,7 @@ namespace Fig::Ast
|
|||||||
class BlockStatementAst : public StatementAst
|
class BlockStatementAst : public StatementAst
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const std::vector<Statement> stmts;
|
std::vector<Statement> stmts;
|
||||||
BlockStatementAst()
|
BlockStatementAst()
|
||||||
{
|
{
|
||||||
type = AstType::BlockStatement;
|
type = AstType::BlockStatement;
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ public:
|
|||||||
case AstType::IfSt:
|
case AstType::IfSt:
|
||||||
printIfSt(std::static_pointer_cast<IfSt>(node), indent);
|
printIfSt(std::static_pointer_cast<IfSt>(node), indent);
|
||||||
break;
|
break;
|
||||||
case AstType::LambdaExpr:
|
|
||||||
printLambdaExpr(std::static_pointer_cast<LambdaExprAst>(node), indent);
|
|
||||||
break;
|
|
||||||
case AstType::TernaryExpr:
|
case AstType::TernaryExpr:
|
||||||
printTernaryExpr(std::static_pointer_cast<TernaryExprAst>(node), indent);
|
printTernaryExpr(std::static_pointer_cast<TernaryExprAst>(node), indent);
|
||||||
break;
|
break;
|
||||||
@@ -147,8 +144,6 @@ private:
|
|||||||
printIndent(indent);
|
printIndent(indent);
|
||||||
std::cout << "FunctionCall\n";
|
std::cout << "FunctionCall\n";
|
||||||
printIndent(indent + 2);
|
printIndent(indent + 2);
|
||||||
std::cout << "FuncName: ";
|
|
||||||
printFString(node->name, 0);
|
|
||||||
printIndent(indent + 2);
|
printIndent(indent + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,14 +170,6 @@ private:
|
|||||||
printIndent(indent + 2);
|
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)
|
void printTernaryExpr(const std::shared_ptr<TernaryExprAst> &node, int indent)
|
||||||
{
|
{
|
||||||
printIndent(indent);
|
printIndent(indent);
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Value/BaseValue.hpp>
|
#include <Value/BaseValue.hpp>
|
||||||
#include <Value/Type.hpp>
|
|
||||||
#include <Ast/functionParameters.hpp>
|
#include <Ast/functionParameters.hpp>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
class Value;
|
||||||
|
|
||||||
/* complex objects */
|
/* complex objects */
|
||||||
struct FunctionStruct
|
struct FunctionStruct
|
||||||
{
|
{
|
||||||
@@ -15,6 +17,10 @@ namespace Fig
|
|||||||
TypeInfo retType;
|
TypeInfo retType;
|
||||||
Ast::BlockStatement body;
|
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) :
|
FunctionStruct(Ast::FunctionParameters _paras, TypeInfo _retType, Ast::BlockStatement _body) :
|
||||||
id(nextId()), // 分配唯一 ID
|
id(nextId()), // 分配唯一 ID
|
||||||
paras(std::move(_paras)),
|
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) :
|
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 &operator=(const FunctionStruct &other) = default;
|
||||||
FunctionStruct(FunctionStruct &&) noexcept = default;
|
FunctionStruct(FunctionStruct &&) noexcept = default;
|
||||||
@@ -61,6 +69,8 @@ namespace Fig
|
|||||||
data = std::make_unique<FunctionStruct>(
|
data = std::make_unique<FunctionStruct>(
|
||||||
std::move(paras), std::move(ret), std::move(body));
|
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
|
bool operator==(const Function &other) const noexcept
|
||||||
{
|
{
|
||||||
if (!data || !other.data) return false;
|
if (!data || !other.data) return false;
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
#include <Ast/FunctionCall.hpp>
|
#include <Ast/FunctionCall.hpp>
|
||||||
#include <Ast/functionParameters.hpp>
|
#include <Ast/functionParameters.hpp>
|
||||||
#include <Ast/FunctionDefSt.hpp>
|
#include <Ast/FunctionDefSt.hpp>
|
||||||
|
#include <Ast/FunctionLiteralExpr.hpp>
|
||||||
#include <Ast/IfSt.hpp>
|
#include <Ast/IfSt.hpp>
|
||||||
#include <Ast/ImplementSt.hpp>
|
#include <Ast/ImplementSt.hpp>
|
||||||
#include <Ast/InitExpr.hpp>
|
#include <Ast/InitExpr.hpp>
|
||||||
#include <Ast/LambdaExpr.hpp>
|
|
||||||
#include <Ast/StructDefSt.hpp>
|
#include <Ast/StructDefSt.hpp>
|
||||||
#include <Ast/TernaryExpr.hpp>
|
#include <Ast/TernaryExpr.hpp>
|
||||||
#include <Ast/UnaryExpr.hpp>
|
#include <Ast/UnaryExpr.hpp>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <builtins.hpp>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <error.hpp>
|
#include <error.hpp>
|
||||||
#include <fig_string.hpp>
|
#include <fig_string.hpp>
|
||||||
#include <ast.hpp>
|
#include <ast.hpp>
|
||||||
@@ -84,6 +82,26 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
globalContext = std::make_shared<Context>(FString(u8"global"));
|
globalContext = std::make_shared<Context>(FString(u8"global"));
|
||||||
currentContext = globalContext;
|
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; }
|
std::shared_ptr<Context> getCurrentContext() { return currentContext; }
|
||||||
@@ -95,6 +113,8 @@ namespace Fig
|
|||||||
|
|
||||||
StatementResult evalStatement(const Ast::Statement &);
|
StatementResult evalStatement(const Ast::Statement &);
|
||||||
|
|
||||||
|
Value evalFunctionCall(const Function &, const Ast::FunctionArguments &, FString fnName = u8"<anonymous>");
|
||||||
|
|
||||||
Value eval(Ast::Expression);
|
Value eval(Ast::Expression);
|
||||||
void run();
|
void run();
|
||||||
void printStackTrace() const;
|
void printStackTrace() const;
|
||||||
|
|||||||
@@ -174,12 +174,19 @@ namespace Fig
|
|||||||
return getBindingPower(op).second;
|
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>
|
template <class _Tp, class... Args>
|
||||||
std::shared_ptr<_Tp> makeAst(Args &&...args)
|
std::shared_ptr<_Tp> makeAst(Args &&...args)
|
||||||
{
|
{
|
||||||
_Tp node(args...);
|
std::shared_ptr<_Tp> ptr = std::make_shared<_Tp>(std::forward<Args>(args)...);
|
||||||
node.setAAI(currentAAI);
|
ptr->setAAI(currentAAI);
|
||||||
return std::shared_ptr<_Tp>(new _Tp(node));
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expectPeek(TokenType type)
|
void expectPeek(TokenType type)
|
||||||
@@ -236,7 +243,6 @@ namespace Fig
|
|||||||
Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool)
|
Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool)
|
||||||
Value __parseValue();
|
Value __parseValue();
|
||||||
Ast::ValueExpr __parseValueExpr();
|
Ast::ValueExpr __parseValueExpr();
|
||||||
Ast::FunctionCall __parseFunctionCall(FString);
|
|
||||||
Ast::FunctionParameters __parseFunctionParameters(); // entry: current is Token::LeftParen
|
Ast::FunctionParameters __parseFunctionParameters(); // entry: current is Token::LeftParen
|
||||||
Ast::Statement __parseStatement(); // entry: (idk)
|
Ast::Statement __parseStatement(); // entry: (idk)
|
||||||
Ast::BlockStatement __parseBlockStatement(); // entry: current is Token::LeftBrace
|
Ast::BlockStatement __parseBlockStatement(); // entry: current is Token::LeftBrace
|
||||||
@@ -246,18 +252,20 @@ namespace Fig
|
|||||||
Ast::Return __parseReturn(); // entry: current is Token::Return
|
Ast::Return __parseReturn(); // entry: current is Token::Return
|
||||||
|
|
||||||
Ast::VarExpr __parseVarExpr(FString);
|
Ast::VarExpr __parseVarExpr(FString);
|
||||||
Ast::LambdaExpr __parseLambdaExpr();
|
|
||||||
Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool)
|
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::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool)
|
||||||
|
|
||||||
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
|
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
|
||||||
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);
|
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);
|
||||||
|
Ast::Expression __parseCall(Ast::Expression);
|
||||||
|
|
||||||
Ast::ListExpr __parseListExpr(); // entry: current is `[`
|
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::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);
|
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
||||||
std::vector<Ast::AstBase> parseAll();
|
std::vector<Ast::AstBase> parseAll();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Fig
|
|||||||
Or, // or
|
Or, // or
|
||||||
Not, // not
|
Not, // not
|
||||||
Import, // import
|
Import, // import
|
||||||
Function, // fun
|
Function, // func
|
||||||
Variable, // var
|
Variable, // var
|
||||||
Const, // const
|
Const, // const
|
||||||
Final, // final
|
Final, // final
|
||||||
@@ -85,7 +85,7 @@ namespace Fig
|
|||||||
RightBrace, // }
|
RightBrace, // }
|
||||||
// LeftArrow, // <-
|
// LeftArrow, // <-
|
||||||
RightArrow, // ->
|
RightArrow, // ->
|
||||||
// DoubleArrow, // =>
|
DoubleArrow, // =>
|
||||||
Equal, // ==
|
Equal, // ==
|
||||||
NotEqual, // !=
|
NotEqual, // !=
|
||||||
LessEqual, // <=
|
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)
|
Value Evaluator::eval(Ast::Expression exp)
|
||||||
{
|
{
|
||||||
using Fig::Ast::AstType;
|
using Fig::Ast::AstType;
|
||||||
@@ -78,7 +190,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return val.value();
|
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: {
|
case AstType::BinaryExpr: {
|
||||||
auto binExp = std::dynamic_pointer_cast<Ast::BinaryExprAst>(exp);
|
auto binExp = std::dynamic_pointer_cast<Ast::BinaryExprAst>(exp);
|
||||||
@@ -89,132 +202,54 @@ namespace Fig
|
|||||||
return evalUnary(unExp);
|
return evalUnary(unExp);
|
||||||
}
|
}
|
||||||
case AstType::FunctionCall: {
|
case AstType::FunctionCall: {
|
||||||
// std::cerr << "Eval: function call...\n";
|
|
||||||
auto fnCall = std::dynamic_pointer_cast<Ast::FunctionCallExpr>(exp);
|
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);
|
Value calleeVal = eval(fnCall->callee);
|
||||||
if (!fnValOpt.has_value())
|
|
||||||
{
|
if (!calleeVal.is<Function>())
|
||||||
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>())
|
|
||||||
{
|
{
|
||||||
static constexpr char NotAFunctionErrorName[] = "NotAFunctionError";
|
static constexpr char NotAFunctionErrorName[] = "NotAFunctionError";
|
||||||
throw EvaluatorError<NotAFunctionErrorName>(FStringView(std::format("'{}' is not a function or callable", fnName.toBasicString())), currentAddressInfo);
|
throw EvaluatorError<NotAFunctionErrorName>(
|
||||||
}
|
FStringView(std::format(
|
||||||
FunctionStruct fnStruct = fnVal.as<Function>().getValue();
|
"'{}' is not a function or callable",
|
||||||
// check argument, all types of parameters
|
calleeVal.toString().toBasicString())),
|
||||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
currentAddressInfo);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast::FunctionCallArgs evaluatedArgs;
|
Function fn = calleeVal.as<Function>();
|
||||||
|
|
||||||
// positional parameters type check
|
FString fnName = u8"<anonymous>";
|
||||||
size_t i;
|
if (auto var = std::dynamic_pointer_cast<Ast::VarExprAst>(fnCall->callee))
|
||||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
fnName = var->name; // try to get function name
|
||||||
{
|
|
||||||
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);
|
return evalFunctionCall(fn, fnCall->arg, fnName);
|
||||||
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]);
|
case AstType::FunctionLiteralExpr: {
|
||||||
TypeInfo actualType = argVal.getTypeInfo();
|
auto fn = std::dynamic_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
||||||
if (expectedType != actualType and expectedType != ValueType::Any)
|
|
||||||
{
|
if (fn->isExprMode())
|
||||||
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();
|
Ast::BlockStatement body = std::make_shared<Ast::BlockStatementAst>();
|
||||||
Value defaultVal = eval(fnParas.defParas[defParamIndex].second.second);
|
body->setAAI(fn->getExprBody()->getAAI());
|
||||||
evaluatedArgs.argv.push_back(defaultVal);
|
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
|
else
|
||||||
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;
|
Ast::BlockStatement body = fn->getBlockBody();
|
||||||
TypeInfo paramType;
|
return Function(
|
||||||
if (j < fnParas.posParas.size())
|
fn->paras,
|
||||||
{
|
ValueType::Any,
|
||||||
paramName = fnParas.posParas[j].first;
|
body
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
case AstType::ListExpr: {
|
case AstType::ListExpr: {
|
||||||
auto listexpr = std::dynamic_pointer_cast<Ast::ListExprAst>(exp);
|
auto listexpr = std::dynamic_pointer_cast<Ast::ListExprAst>(exp);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Fig
|
|||||||
{FString(u8":="), TokenType::Walrus},
|
{FString(u8":="), TokenType::Walrus},
|
||||||
{FString(u8"**"), TokenType::Power},
|
{FString(u8"**"), TokenType::Power},
|
||||||
{FString(u8"->"), TokenType::RightArrow},
|
{FString(u8"->"), TokenType::RightArrow},
|
||||||
|
{FString(u8"=>"), TokenType::DoubleArrow},
|
||||||
|
|
||||||
// 单字符
|
// 单字符
|
||||||
{FString(u8"+"), TokenType::Plus},
|
{FString(u8"+"), TokenType::Plus},
|
||||||
@@ -62,7 +63,7 @@ namespace Fig
|
|||||||
{FString(u8"or"), TokenType::Or},
|
{FString(u8"or"), TokenType::Or},
|
||||||
{FString(u8"not"), TokenType::Not},
|
{FString(u8"not"), TokenType::Not},
|
||||||
{FString(u8"import"), TokenType::Import},
|
{FString(u8"import"), TokenType::Import},
|
||||||
{FString(u8"fun"), TokenType::Function},
|
{FString(u8"func"), TokenType::Function},
|
||||||
{FString(u8"var"), TokenType::Variable},
|
{FString(u8"var"), TokenType::Variable},
|
||||||
{FString(u8"const"), TokenType::Const},
|
{FString(u8"const"), TokenType::Const},
|
||||||
{FString(u8"final"), TokenType::Final},
|
{FString(u8"final"), TokenType::Final},
|
||||||
|
|||||||
128
src/parser.cpp
128
src/parser.cpp
@@ -361,20 +361,17 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
// stmt = __parseVarDef();
|
// stmt = __parseVarDef();
|
||||||
// expect(TokenType::Semicolon);
|
// expect(TokenType::Semicolon);
|
||||||
// next();
|
next(); // consume `public`
|
||||||
if (isNext(TokenType::Variable) || isNext(TokenType::Const))
|
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||||
{
|
{
|
||||||
next(); // consume `public`
|
|
||||||
stmt = __parseVarDef(true);
|
stmt = __parseVarDef(true);
|
||||||
}
|
}
|
||||||
else if (isNext(TokenType::Function))
|
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||||
{
|
{
|
||||||
next(); // consume `public`
|
|
||||||
expectPeek(TokenType::Identifier);
|
|
||||||
next();
|
next();
|
||||||
stmt = __parseFunctionDef(true);
|
stmt = __parseFunctionDef(true);
|
||||||
}
|
}
|
||||||
else if (isNext(TokenType::Struct))
|
else if (isThis(TokenType::Struct))
|
||||||
{
|
{
|
||||||
stmt = __parseStructDef(true);
|
stmt = __parseStructDef(true);
|
||||||
}
|
}
|
||||||
@@ -387,9 +384,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
stmt = __parseVarDef(false);
|
stmt = __parseVarDef(false);
|
||||||
}
|
}
|
||||||
else if (isThis(TokenType::Function))
|
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||||
{
|
{
|
||||||
expectPeek(TokenType::Identifier, u8"function name");
|
|
||||||
next();
|
next();
|
||||||
stmt = __parseFunctionDef(false);
|
stmt = __parseFunctionDef(false);
|
||||||
}
|
}
|
||||||
@@ -523,55 +519,11 @@ namespace Fig
|
|||||||
return makeAst<Ast::ReturnSt>(retValue);
|
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)
|
Ast::VarExpr Parser::__parseVarExpr(FString name)
|
||||||
{
|
{
|
||||||
return makeAst<Ast::VarExprAst>(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)
|
Ast::UnaryExpr Parser::__parsePrefix(Ast::Operator op, Precedence bp)
|
||||||
{
|
{
|
||||||
return makeAst<Ast::UnaryExprAst>(op, parseExpression(bp));
|
return makeAst<Ast::UnaryExprAst>(op, parseExpression(bp));
|
||||||
@@ -581,6 +533,32 @@ namespace Fig
|
|||||||
return makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp));
|
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()
|
Ast::ListExpr Parser::__parseListExpr()
|
||||||
{
|
{
|
||||||
// entry: current is `[`
|
// entry: current is `[`
|
||||||
@@ -739,6 +717,27 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
return nullptr; // to suppress compiler warning
|
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 Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
|
||||||
{
|
{
|
||||||
Ast::Expression lhs;
|
Ast::Expression lhs;
|
||||||
@@ -764,6 +763,17 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
lhs = __parseMapExpr(); // auto consume
|
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())
|
else if (tok.isLiteral())
|
||||||
{
|
{
|
||||||
lhs = __parseValueExpr();
|
lhs = __parseValueExpr();
|
||||||
@@ -773,11 +783,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
FString id = tok.getValue();
|
FString id = tok.getValue();
|
||||||
next();
|
next();
|
||||||
if (currentToken().getType() == TokenType::LeftParen)
|
if (currentToken().getType() == TokenType::LeftBrace)
|
||||||
{
|
|
||||||
lhs = __parseFunctionCall(id); // foo(...)
|
|
||||||
}
|
|
||||||
else if (currentToken().getType() == TokenType::LeftBrace)
|
|
||||||
{
|
{
|
||||||
lhs = __parseInitExpr(id); // a_struct{init...}
|
lhs = __parseInitExpr(id); // a_struct{init...}
|
||||||
}
|
}
|
||||||
@@ -803,6 +809,12 @@ namespace Fig
|
|||||||
tok = currentToken();
|
tok = currentToken();
|
||||||
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break;
|
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break;
|
||||||
|
|
||||||
|
if (tok.getType() == TokenType::LeftParen)
|
||||||
|
{
|
||||||
|
lhs = __parseCall(lhs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// ternary
|
// ternary
|
||||||
if (tok.getType() == TokenType::Question)
|
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