16 Commits

Author SHA1 Message Date
ca4ae143b4 v0.4.2-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 43s
Release Build / build-linux-x64 (push) Successful in 50s
[Fix][Impl] 为了消除类构造带来的语法歧义,同时保持实现简洁和括号省略的语法,自此版本,引入了 `new` 操作符
            造成歧义的原方法:
                if a == A{}
            条件是 a == A,还是 a == A{} ?

            因此,现在使用 new a_struct{}来构造类
[Opti] 相较于 Fig v0.4.1-alpha版本,release O3同编译条件下
       Fib普通递归法性能提升 ~50%
       具体方式:
            增加了小整数优化,-128~127的整数现在会直接从IntPool获取而不是新构造
            ...忘了
[Fix] 类构造 shorthand模式忘写了,现在补上了
[Feat][Impl] 类型声明现在接受一个表达式,原为Identifier。实现 var start: time.Time = time.now() 的效果
             这是符合语法和语言特性的支持,类型为一等公民。类似Python的 <class 'type'>

[Impl] 修改了部分错误输出的细节
2026-01-22 08:24:14 +08:00
21641f888e 恢复原来的构建逻辑
All checks were successful
Release Build / build-windows-x64 (push) Successful in 2m55s
Release Build / build-linux-x64 (push) Successful in 4m41s
2026-01-19 17:33:52 +08:00
def69e031f qswl x3 2026-01-19 17:26:46 +08:00
009a70fc64 气死我了x2 2026-01-19 17:24:29 +08:00
e01b4e9849 气死我了 2026-01-19 17:19:12 +08:00
da262a4cf1 尝试修复 build.yml 版本构建 2026-01-19 17:09:44 +08:00
f76e28ee8d 修改 build action 2026-01-19 16:57:57 +08:00
a324cf17f6 尝试修复windows构建版本获取问题,代码是ds写的。我不会actions
Some checks failed
Release Build / build-windows-x64 (push) Failing after 32s
Release Build / build-linux-x64 (push) Has been cancelled
2026-01-19 16:27:14 +08:00
caf058dd55 [VER] v0.4.1-alpha
Some checks failed
Release Build / build-windows-x64 (push) Failing after 3m2s
Release Build / build-linux-x64 (push) Has been cancelled
[Fix] 修复struct定义创建instanceCtx时拷贝类方法错误的Bug,表现在同一类的2个不同实例内置函数一样的问题
      (即 addr A != addr B, addr A.method == addr B.method)
      修复后为 (addr A != addr B, addr A.method != addr B.method)
      方法的closureContext指向instance的Context
      修复后 std.time可以正常使用
2026-01-19 16:10:12 +08:00
9e3f17711f [VER] 0.4.0-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 54s
Release Build / build-linux-x64 (push) Successful in 1m21s
[Fix] 修复恶性Bug: Parser: parseExpression没有正确解析二元表达式,没有用到 right binding power的问题,表现在生成类似 a * b * c时,结果为 a * (b * c) 的Bug
[Impl][Fix] 修复跨文件(如import)报错信息错误的问题,现在Ast跟踪保存文件信息,报错统一从Error父类获取
[...] 忘了,好困不管了
2026-01-19 04:13:55 +08:00
d398d457b5 [VER] v0.3.9-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 1m0s
Release Build / build-linux-x64 (push) Successful in 1m2s
[Feat] is 操作符现在可以直接判断内置数据类型, 如 10 is Int
[Fix] evalMemberExpr的lhs可以为右值,修复原来限制为左值的BUG,如调用一个函数返回结果为struct且访问member触发此bug
[Impl] 可更换的std::dynamic_pointer_cast更换为static版本,更快!
[Feat] 增加标准库 std.time,以及用到的builtin: __ftime_now_ns,但目前 Time类有点BUG
[...] 剩下的忘了
2026-01-15 17:51:01 +08:00
ccf80536b3 [Fix] 蠢蛋clang!
All checks were successful
Release Build / build-windows-x64 (push) Successful in 47s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 21:35:48 +08:00
13fdbec0c4 [VER] v0.3.8-alpha
Some checks failed
Release Build / build-linux-x64 (push) Failing after 18s
Release Build / build-windows-x64 (push) Successful in 46s
[Impl][Fix] 更改resolveModulePath实现,使用绝对路径查找内置库
2026-01-14 21:31:11 +08:00
99e00492f5 删除蠢蛋注释
All checks were successful
Release Build / build-windows-x64 (push) Successful in 46s
Release Build / build-linux-x64 (push) Successful in 59s
2026-01-14 17:37:27 +08:00
310d79acc5 我忘记改版本号了
Some checks failed
Release Build / build-windows-x64 (push) Failing after 48s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 17:34:24 +08:00
e28921ae02 [VER] 0.3.7-alpha
[Fix] 修复科学表达式数字解析的问题(Lexer引起) 由 Satklomi发现,感谢
[Feat] 增加Compiler相关定义,将开发BytecodeVM
[Tip] Evaluator进入Bug fix阶段,新功能延缓开发。转向VM
2026-01-14 17:28:38 +08:00
53 changed files with 1960 additions and 976 deletions

View File

@@ -10,4 +10,70 @@ invalid!
*/ */
const Pi := 3.14; // recommended, auto detect type const Pi := 3.14; // recommended, auto detect type
// equal -> const Pi: Double = 3.14; // equal -> const Pi: Double = 3.14;
/*
In fig, we have 13 builtin-type
01 Any
02 Null
03 Int
04 String
05 Bool
06 Double
07 Function
08 StructType
09 StructInstance
10 List
11 Map
12 Module
13 InterfaceType
3, 4, 5, 6, 10, 11 are initable
value system:
object is immutable
(included basic types: Int, String...)
`variable` is a name, refers to an object
assignment is to bind name to value
Example: var a := 10;
[name] 'a' ---> variable slot (name, declared type, access modifier, [value) ---> ObjectPtr ---> raw Object class
bind bind (shared_ptr)
For example:
var a := 10;
var b := 10;
`a` and `b` reference to the same object in memory
a = 20;
now a refers to a new object (20, Int)
what about complex types?
they actually have same behaviors with basic types
var a := [1, 2, 3, 4];
var b := a;
> a
[1, 2, 3, 4]
> b
[1, 2, 3, 4]
set a[0] to 5
> a
[5, 2, 3, 4]
> b
[5, 2, 3, 4]
Why did such a result occur?
" `a` and `b` reference to the same object in memory "
If you wish to obtain a copy, use List {a} to deeply copy it
*/

View File

@@ -0,0 +1,65 @@
import std.io;
import std.time;
func benchmark(fn: Function, arg: Any) -> Null
{
io.println("Testing fn:", fn, "with arg:", arg);
const start := time.now();
const result := fn(arg);
const end := time.now();
const duration := new time.Time{
end.since(start)
};
io.println("=" * 50);
io.println("fn returns:", result, "\n");
io.println("Cost:", duration.toSeconds(), "s");
io.println(" ", duration.toMillis(), "ms");
}
var memo := {};
func fib_memo(x)
{
if memo.contains(x)
{
return memo.get(x);
}
if x <= 1
{
memo[x] = x;
return x;
}
var result := fib_memo(x - 1) + fib_memo(x - 2);
memo[x] = result;
return result;
}
func fib_iter(n)
{
var a := 0;
var b := 1;
for var i := 0; i < n; i = i + 1
{
var temp := a + b;
a = b;
b = temp;
}
return a;
}
func fib(x)
{
if x <= 1
{
return x;
}
return fib(x - 1) + fib(x - 2);
}
const n := 28;
benchmark(fib, n);
benchmark(fib_memo, n);
benchmark(fib_iter, n);

View File

@@ -2,7 +2,7 @@
"name": "fig-vscode", "name": "fig-vscode",
"displayName": "Fig Language", "displayName": "Fig Language",
"description": "VSCode extension for Fig language with syntax highlighting", "description": "VSCode extension for Fig language with syntax highlighting",
"version": "0.0.2", "version": "0.4.2",
"publisher": "PuqiAR", "publisher": "PuqiAR",
"engines": { "engines": {
"vscode": "^1.90.0" "vscode": "^1.90.0"

View File

@@ -57,7 +57,7 @@
"patterns": [ "patterns": [
{ {
"name": "keyword.control.fig", "name": "keyword.control.fig",
"match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|struct|interface|impl|public|return|break|continue|try|catch|throw)\\b" "match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|new|struct|interface|impl|public|return|break|continue|try|catch|throw)\\b"
}, },
{ "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" } { "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" }
] ]

View File

@@ -7,7 +7,7 @@ namespace Fig::Ast
class InitExprAst final : public ExpressionAst class InitExprAst final : public ExpressionAst
{ {
public: public:
FString structName; Expression structe;
std::vector<std::pair<FString, Expression>> args; std::vector<std::pair<FString, Expression>> args;
@@ -30,8 +30,8 @@ namespace Fig::Ast
type = AstType::InitExpr; type = AstType::InitExpr;
} }
InitExprAst(FString _structName, std::vector<std::pair<FString, Expression>> _args, InitMode _initMode) : InitExprAst(Expression _structe, std::vector<std::pair<FString, Expression>> _args, InitMode _initMode) :
structName(std::move(_structName)), args(std::move(_args)), initMode(_initMode) structe(std::move(_structe)), args(std::move(_args)), initMode(_initMode)
{ {
type = AstType::InitExpr; type = AstType::InitExpr;
} }

View File

@@ -23,14 +23,14 @@ namespace Fig::Ast
FString name; FString name;
FunctionParameters paras; FunctionParameters paras;
bool isPublic; bool isPublic;
FString retType; Expression retType;
BlockStatement body; BlockStatement body;
FunctionDefSt() :
retType(ValueType::Null.name) FunctionDefSt()
{ {
type = AstType::FunctionDefSt; type = AstType::FunctionDefSt;
} }
FunctionDefSt(FString _name, FunctionParameters _paras, bool _isPublic, FString _retType, BlockStatement _body) FunctionDefSt(FString _name, FunctionParameters _paras, bool _isPublic, Expression _retType, BlockStatement _body)
{ {
type = AstType::FunctionDefSt; type = AstType::FunctionDefSt;

View File

@@ -25,7 +25,7 @@ namespace Fig::Ast
{ {
FString name; FString name;
FunctionParameters paras; FunctionParameters paras;
FString returnType; Expression returnType;
BlockStatement defaultBody = nullptr; // nullptr is non-default func BlockStatement defaultBody = nullptr; // nullptr is non-default func

View File

@@ -12,12 +12,12 @@ namespace Fig::Ast
{ {
AccessModifier am; AccessModifier am;
FString fieldName; FString fieldName;
FString tiName; Expression declaredType;
Expression defaultValueExpr; Expression defaultValueExpr;
StructDefField() {} StructDefField() {}
StructDefField(AccessModifier _am, FString _fieldName, FString _tiName, Expression _defaultValueExpr) : StructDefField(AccessModifier _am, FString _fieldName, Expression _declaredType, Expression _defaultValueExpr) :
am(std::move(_am)), fieldName(std::move(_fieldName)), tiName(std::move(_tiName)), defaultValueExpr(std::move(_defaultValueExpr)) am(std::move(_am)), fieldName(std::move(_fieldName)), declaredType(std::move(_declaredType)), defaultValueExpr(std::move(_defaultValueExpr))
{ {
} }
}; };

View File

@@ -11,22 +11,28 @@ namespace Fig::Ast
bool isPublic; bool isPublic;
bool isConst; bool isConst;
FString name; FString name;
FString typeName; // FString typeName;
Expression declaredType;
Expression expr; Expression expr;
VarDefAst() : bool followupType;
typeName(ValueType::Any.name)
VarDefAst()
{ {
type = AstType::VarDefSt; type = AstType::VarDefSt;
declaredType = nullptr;
expr = nullptr;
followupType = false;
} }
VarDefAst(bool _isPublic, bool _isConst, FString _name, FString _info, Expression _expr) : VarDefAst(bool _isPublic, bool _isConst, FString _name, Expression _declaredType, Expression _expr, bool _followupType)
typeName(std::move(_info))
{ {
type = AstType::VarDefSt; type = AstType::VarDefSt;
isPublic = _isPublic; isPublic = _isPublic;
isConst = _isConst; isConst = _isConst;
name = std::move(_name); name = std::move(_name);
declaredType = std::move(_declaredType);
expr = std::move(_expr); expr = std::move(_expr);
followupType = _followupType;
} }
}; };

View File

@@ -26,14 +26,15 @@ namespace Fig::Ast
TernaryExpr, TernaryExpr,
/* Postfix */ /* Postfix */
MemberExpr, // a.b MemberExpr, // a.b
IndexExpr, // a[b] IndexExpr, // a[b]
FunctionCall, // a() FunctionCall, // a()
/* Literals */ /* Literals */
ListExpr, // [1, "2", 3 ListExpr, // [1, "2", 3
TupleExpr, // (1, 2, 3) TupleExpr, // (1, 2, 3)
MapExpr, // {a: 1} MapExpr, // {a: 1}
InitExpr, // struct{"123", 456} InitExpr, // struct{"123", 456}
FunctionLiteralExpr, FunctionLiteralExpr,
@@ -100,6 +101,8 @@ namespace Fig::Ast
struct AstAddressInfo struct AstAddressInfo
{ {
size_t line, column; size_t line, column;
std::shared_ptr<FString> sourcePath;
std::shared_ptr<std::vector<FString>> sourceLines;
}; };
class _AstBase class _AstBase
@@ -117,30 +120,20 @@ namespace Fig::Ast
_AstBase() {} _AstBase() {}
void setAAI(AstAddressInfo _aai) void setAAI(AstAddressInfo _aai) { aai = std::move(_aai); }
{
aai = std::move(_aai);
}
virtual FString typeName() virtual FString typeName()
{ {
return FString::fromStringView( return FString::fromStringView(FStringView::fromBasicStringView(magic_enum::enum_name(type)));
FStringView::fromBasicStringView(magic_enum::enum_name(type)));
} }
virtual FString toString() virtual FString toString()
{ {
return FString(std::format("<Base Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column)); return FString(std::format("<Base Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
} }
AstAddressInfo getAAI() AstAddressInfo getAAI() { return aai; }
{
return aai;
}
AstType getType() AstType getType() { return type; }
{
return type;
}
}; };
class StatementAst : public _AstBase class StatementAst : public _AstBase
@@ -148,10 +141,7 @@ namespace Fig::Ast
public: public:
using _AstBase::_AstBase; using _AstBase::_AstBase;
using _AstBase::operator=; using _AstBase::operator=;
StatementAst() StatementAst() { type = AstType::StatementBase; }
{
type = AstType::StatementBase;
}
virtual FString toString() override virtual FString toString() override
{ {
@@ -162,10 +152,7 @@ namespace Fig::Ast
class EofStmt final : public StatementAst class EofStmt final : public StatementAst
{ {
public: public:
EofStmt() EofStmt() { type = AstType::StatementBase; }
{
type = AstType::StatementBase;
}
virtual FString toString() override virtual FString toString() override
{ {
@@ -178,10 +165,7 @@ namespace Fig::Ast
public: public:
using _AstBase::_AstBase; using _AstBase::_AstBase;
using _AstBase::operator=; using _AstBase::operator=;
ExpressionAst() ExpressionAst() { type = AstType::ExpressionBase; }
{
type = AstType::ExpressionBase;
}
virtual FString toString() override virtual FString toString() override
{ {
@@ -238,41 +222,24 @@ namespace Fig::Ast
}; };
static const std::unordered_set<Operator> unaryOps{ static const std::unordered_set<Operator> unaryOps{
Operator::Not, Operator::Not, // !
Operator::Subtract, Operator::Subtract, // -
Operator::BitNot, Operator::BitNot, // ~
Operator::BitAnd, // reference operator &
}; };
static const std::unordered_set<Operator> binaryOps{ static const std::unordered_set<Operator> binaryOps{
Operator::Add, Operator::Add, Operator::Subtract, Operator::Multiply, Operator::Divide,
Operator::Subtract, Operator::Modulo, Operator::Power, Operator::And, Operator::Or,
Operator::Multiply,
Operator::Divide,
Operator::Modulo,
Operator::Power,
Operator::And,
Operator::Or,
Operator::Equal, Operator::Equal, Operator::NotEqual, Operator::Less, Operator::LessEqual,
Operator::NotEqual, Operator::Greater, Operator::GreaterEqual, Operator::Is,
Operator::Less,
Operator::LessEqual,
Operator::Greater,
Operator::GreaterEqual,
Operator::Is,
Operator::BitAnd, Operator::BitAnd, Operator::BitOr, Operator::BitXor, Operator::BitNot,
Operator::BitOr, Operator::ShiftLeft, Operator::ShiftRight,
Operator::BitXor,
Operator::BitNot,
Operator::ShiftLeft,
Operator::ShiftRight,
Operator::Assign, Operator::Assign, Operator::PlusAssign, Operator::MinusAssign, Operator::AsteriskAssign,
Operator::PlusAssign, Operator::SlashAssign, Operator::CaretAssign
Operator::MinusAssign,
Operator::AsteriskAssign,
Operator::SlashAssign,
Operator::CaretAssign
// Operator::Walrus, // Operator::Walrus,
// Operator::Dot // Operator::Dot
@@ -348,19 +315,9 @@ namespace Fig::Ast
{ {
public: public:
std::vector<Statement> stmts; std::vector<Statement> stmts;
BlockStatementAst() BlockStatementAst() { type = AstType::BlockStatement; }
{ BlockStatementAst(std::vector<Statement> _stmts) : stmts(std::move(_stmts)) { type = AstType::BlockStatement; }
type = AstType::BlockStatement; virtual FString typeName() override { return FString(u8"BlockStatement"); }
}
BlockStatementAst(std::vector<Statement> _stmts) :
stmts(std::move(_stmts))
{
type = AstType::BlockStatement;
}
virtual FString typeName() override
{
return FString(u8"BlockStatement");
}
virtual FString toString() override virtual FString toString() override
{ {
return FString(std::format("<StmtAst '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column)); return FString(std::format("<StmtAst '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));

125
src/Bytecode/Bytecode.hpp Normal file
View File

@@ -0,0 +1,125 @@
#pragma once
/*
从树遍历到虚拟机!
*/
#include "Core/fig_string.hpp"
#include "Utils/magic_enum/magic_enum.hpp"
#include <cstdint>
#include <format>
#include <string_view>
namespace Fig
{
using OpCodeType = uint8_t;
enum class Bytecode : OpCodeType
{
HALT = 0x01, // 程序终止,后跟 8 位退出码
POP = 0x10,
LOAD_NULL = 0x20,
LOAD_TRUE = 0x21,
LOAD_FALSE = 0x22,
LOAD_CON8 = 0x23, // 跟 8 位索引 (0 - 255)
LOAD_CON16 = 0x24, // 跟 16 位索引 (255 - 65535)
LOAD_CON32 = 0x25, // 跟 32 位索引 (65536 - 2^32-1)
ADD = 0x30, // +
SUB = 0x31, // -
MUL = 0x32, // *
DIV = 0x33, // /
MOD = 0x34, // %
AND = 0x40, // &
OR = 0x41, // |
XOR = 0x42, // ~
NOT = 0x43, // ! (not)
EQ = 0x50, // ==
GT = 0x51, // >
GTEQ = 0x52, // >=
LT = 0x53, // <
LTEQ = 0x54, // <=
JUMP16 = 0x60, // 跟 16 位索引 无条件
JUMP32 = 0x61, // 跟 32 位索引 无条件
JUMP16_IF_TRUE = 0x62, // 跟 16 位索引 栈顶为真跳转
JUMP32_IF_TRUE = 0x63, // 跟 32 位索引 栈顶为真跳转
JUMP16_IF_FALSE = 0x64, // 跟 16 位索引 栈顶为假跳转
JUMP32_IF_FALSE = 0x65, // 跟 32 位索引 栈顶为假跳转
LOAD_LOCAL16 = 0x70, // 后跟 16 位索引
LOAD_LOCAL32 = 0x71, // 后跟 32 位索引
};
inline FString bytecode2string(Bytecode code)
{
const std::string_view &name = magic_enum::enum_name(code);
return FString(FStringView(name));
}
inline FString reverseCompile(const std::vector<uint8_t> &src)
{
assert(src.size() >= 1);
FString result;
using enum Bytecode;
for (size_t i = 0; i < src.size();)
{
Bytecode code = Bytecode(src[i]);
switch (code)
{
case HALT: {
uint8_t quitCode = src[++i];
result += FString(std::format("HALT {}", static_cast<uint8_t>(quitCode))) + u8"\n";
break;
}
case LOAD_CON8: {
uint8_t id = src[++i];
result += FString(std::format("LOAD_CON8 {}", static_cast<uint8_t>(id))) + u8"\n";
break;
}
case LOAD_CON16:
case JUMP16:
case JUMP16_IF_TRUE:
case JUMP16_IF_FALSE:
case LOAD_LOCAL16: {
uint8_t high = src[++i];
uint8_t low = src[++i];
int32_t id = (high << 8) | low;
result += FString(std::format("{} {}", bytecode2string(code).toBasicString(), id))
+ u8"\n";
break;
}
case LOAD_CON32:
case JUMP32:
case JUMP32_IF_TRUE:
case JUMP32_IF_FALSE:
case LOAD_LOCAL32: {
uint32_t b0 = static_cast<uint32_t>(src[++i]);
uint32_t b1 = static_cast<uint32_t>(src[++i]);
uint32_t b2 = static_cast<uint32_t>(src[++i]);
uint32_t b3 = static_cast<uint32_t>(src[++i]);
uint32_t id = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
result += FString(std::format("{} {}", bytecode2string(code).toBasicString(), id))
+ u8"\n";
break;
}
default: {
result += bytecode2string(code) + u8"\n";
}
}
++i;
}
return result;
}
}; // namespace Fig

21
src/Compiler/Compiler.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <Ast/astBase.hpp>
#include <Compiler/Compiler.hpp>
#include <memory>
namespace Fig
{
void Compiler::compile(Ast::Statement stmt)
{
using enum Ast::AstType;
using namespace Ast;
Ast::AstType type = stmt->getType();
switch (type)
{
case VarDefSt: {
auto vd = std::static_pointer_cast<VarDefAst>(stmt);
const FString name = vd->name;
}
}
}
}; // namespace Fig

32
src/Compiler/Compiler.hpp Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include "Ast/astBase.hpp"
#include <Ast/ast.hpp>
#include <Bytecode/Bytecode.hpp>
#include <VMValue/VMValue.hpp>
#include <vector>
namespace Fig
{
class Compiler
{
private:
std::vector<Ast::Statement> source;
std::vector<OpCodeType> output; // std::vector<uint8_t>
std::vector<Value> constants;
public:
std::vector<OpCodeType> getOutput() const { return output; }
std::vector<Value> getConstantPool() const { return constants; }
Compiler() {}
Compiler(std::vector<Ast::Statement> _source) : source(std::move(_source)) {}
void compile_expr(Ast::Expression);
void compile(Ast::Statement);
void CompileAll();
};
}; // namespace Fig

View File

@@ -4,7 +4,7 @@
#include <cstdint> #include <cstdint>
#include <string_view> #include <string_view>
#define __FCORE_VERSION "0.3.6-alpha" #define __FCORE_VERSION "0.4.2-alpha"
#if defined(_WIN32) #if defined(_WIN32)
#define __FCORE_PLATFORM "Windows" #define __FCORE_PLATFORM "Windows"

View File

@@ -0,0 +1,21 @@
#pragma once
#include <filesystem>
#ifdef _WIN32
#include <libloaderapi.h>
#endif
namespace Fig
{
inline std::filesystem::path getExecutablePath()
{
#ifdef _WIN32
wchar_t buffer[MAX_PATH];
GetModuleFileNameW(nullptr, buffer, MAX_PATH);
return std::filesystem::path(buffer);
#else
return std::filesystem::canonical("/proc/self/exe");
#endif
}
}; // namespace Fig

View File

@@ -43,6 +43,10 @@ namespace Fig
{ {
return FString(toBasicString() + x.toBasicString()); return FString(toBasicString() + x.toBasicString());
} }
FString operator+(const char8_t *c)
{
return FString(*this + std::u8string(c));
}
explicit FString(const std::u8string &str) explicit FString(const std::u8string &str)
{ {

18
src/Core/runtimeTime.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include <Core/runtimeTime.hpp>
#include <cassert>
namespace Fig::Time
{
Clock::time_point start_time;
void init()
{
static bool flag = false;
if (flag)
{
assert(false);
}
start_time = Clock::now();
flag = true;
}
};

10
src/Core/runtimeTime.hpp Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <chrono>
namespace Fig::Time
{
using Clock = std::chrono::steady_clock;
extern Clock::time_point start_time; // since process start
void init();
};

View File

@@ -6,6 +6,7 @@
#include <format> #include <format>
#include <source_location> #include <source_location>
#include <string> #include <string>
#include <vector>
namespace Fig namespace Fig
{ {
@@ -16,8 +17,10 @@ namespace Fig
explicit AddressableError(FString _msg, explicit AddressableError(FString _msg,
size_t _line, size_t _line,
size_t _column, size_t _column,
FString _sourcePath,
std::vector<FString> _sourceLines,
std::source_location loc = std::source_location::current()) : std::source_location loc = std::source_location::current()) :
src_loc(loc), line(_line), column(_column) src_loc(loc), line(_line), column(_column), sourcePath(std::move(_sourcePath)), sourceLines(std::move(_sourceLines))
{ {
message = _msg; message = _msg;
} }
@@ -33,9 +36,11 @@ namespace Fig
} }
std::source_location src_loc; std::source_location src_loc;
size_t getLine() const { return line; } virtual size_t getLine() const { return line; }
size_t getColumn() const { return column; } virtual size_t getColumn() const { return column; }
FString getMessage() const { return message; } FString getMessage() const { return message; }
FString getSourcePath() const { return sourcePath; }
std::vector<FString> getSourceLines() const { return sourceLines; }
virtual FString getErrorType() const virtual FString getErrorType() const
{ {
@@ -45,6 +50,9 @@ namespace Fig
protected: protected:
size_t line, column; size_t line, column;
FString message; FString message;
FString sourcePath;
std::vector<FString> sourceLines;
}; };
class UnaddressableError : public std::exception class UnaddressableError : public std::exception
@@ -84,14 +92,6 @@ namespace Fig
public: public:
using AddressableError::AddressableError; using AddressableError::AddressableError;
explicit SyntaxError(FString _msg,
size_t _line,
size_t _column,
std::source_location loc = std::source_location::current()) :
AddressableError(_msg, _line, _column, loc)
{
}
virtual FString toString() const override virtual FString toString() const override
{ {
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name()); std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());

View File

@@ -98,8 +98,11 @@ namespace Fig
} }
inline void logAddressableError(const AddressableError &err, FString fileName, std::vector<FString> sourceLines) inline void logAddressableError(const AddressableError &err)
{ {
const FString &fileName = err.getSourcePath();
const std::vector<FString> &sourceLines = err.getSourceLines();
std::print("\n"); std::print("\n");
namespace TC = TerminalColors; namespace TC = TerminalColors;
coloredPrint(TC::LightWhite, "An error occurred! "); coloredPrint(TC::LightWhite, "An error occurred! ");

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Ast/Statements/InterfaceDefSt.hpp"
#include "Value/interface.hpp" #include "Value/interface.hpp"
#include <Value/Type.hpp> #include <Value/Type.hpp>
#include <algorithm> #include <algorithm>
@@ -33,17 +34,13 @@ namespace Fig
std::unordered_map<std::size_t, FString> functionNames; std::unordered_map<std::size_t, FString> functionNames;
// implRegistry <Struct, ordered list of ImplRecord> // implRegistry <Struct, ordered list of ImplRecord>
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
implRegistry;
public: public:
ContextPtr parent; ContextPtr parent;
Context(const Context &) = default; Context(const Context &) = default;
Context(const FString &name, ContextPtr p = nullptr) : Context(const FString &name, ContextPtr p = nullptr) : scopeName(name), parent(p) {}
scopeName(name), parent(p)
{
}
void setParent(ContextPtr _parent) { parent = _parent; } void setParent(ContextPtr _parent) { parent = _parent; }
@@ -55,37 +52,28 @@ namespace Fig
{ {
variables.insert(c.variables.begin(), c.variables.end()); variables.insert(c.variables.begin(), c.variables.end());
functions.insert(c.functions.begin(), c.functions.end()); functions.insert(c.functions.begin(), c.functions.end());
functionNames.insert(c.functionNames.begin(), functionNames.insert(c.functionNames.begin(), c.functionNames.end());
c.functionNames.end());
implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end()); implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end());
// structTypeNames.insert(c.structTypeNames.begin(), // structTypeNames.insert(c.structTypeNames.begin(),
// c.structTypeNames.end()); // c.structTypeNames.end());
} }
std::unordered_map<size_t, Function> getFunctions() const std::unordered_map<size_t, Function> getFunctions() const { return functions; }
{
return functions;
}
std::shared_ptr<VariableSlot> get(const FString &name) std::shared_ptr<VariableSlot> get(const FString &name)
{ {
auto it = variables.find(name); auto it = variables.find(name);
if (it != variables.end()) return it->second; if (it != variables.end()) return it->second;
if (parent) return parent->get(name); if (parent) return parent->get(name);
throw RuntimeError(FString(std::format("Variable '{}' not defined", throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
name.toBasicString())));
} }
AccessModifier getAccessModifier(const FString &name) AccessModifier getAccessModifier(const FString &name)
{ {
if (variables.contains(name)) { return variables[name]->am; } if (variables.contains(name)) { return variables[name]->am; }
else if (parent != nullptr) else if (parent != nullptr) { return parent->getAccessModifier(name); }
{
return parent->getAccessModifier(name);
}
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
bool isVariableMutable(const FString &name) bool isVariableMutable(const FString &name)
@@ -104,16 +92,14 @@ namespace Fig
{ {
if (!isVariableMutable(name)) if (!isVariableMutable(name))
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' is immutable", name.toBasicString())));
"Variable '{}' is immutable", name.toBasicString())));
} }
variables[name]->value = value; variables[name]->value = value;
} }
else if (parent != nullptr) { parent->set(name, value); } else if (parent != nullptr) { parent->set(name, value); }
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
void _update(const FString &name, ObjectPtr value) void _update(const FString &name, ObjectPtr value)
@@ -122,8 +108,7 @@ namespace Fig
else if (parent != nullptr) { parent->_update(name, value); } else if (parent != nullptr) { parent->_update(name, value); }
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
void def(const FString &name, void def(const FString &name,
@@ -133,14 +118,11 @@ namespace Fig
{ {
if (containsInThisScope(name)) if (containsInThisScope(name))
{ {
throw RuntimeError(FString( throw RuntimeError(
std::format("Variable '{}' already defined in this scope", FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
name.toBasicString())));
} }
variables[name] = variables[name] = std::make_shared<VariableSlot>(name, value, ti, am);
std::make_shared<VariableSlot>(name, value, ti, am); if (ti == ValueType::Function and value->getTypeInfo() == ValueType::Function)
if (ti == ValueType::Function
and value->getTypeInfo() == ValueType::Function)
{ {
auto &fn = value->as<Function>(); auto &fn = value->as<Function>();
functions[fn.id] = fn; functions[fn.id] = fn;
@@ -152,19 +134,42 @@ namespace Fig
// structTypeNames[st.id] = name; // structTypeNames[st.id] = name;
// } // }
} }
void
defReference(const FString &name, const TypeInfo &ti, AccessModifier am, std::shared_ptr<VariableSlot> target)
{
if (containsInThisScope(name))
{
throw RuntimeError(
FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
}
variables[name] = std::make_shared<VariableSlot>(
name,
target->value,
ti,
am,
true,
target
);
}
std::optional<Function> getFunction(std::size_t id) std::optional<Function> getFunction(std::size_t id)
{ {
auto it = functions.find(id); auto it = functions.find(id);
if (it != functions.end()) { return it->second; } if (it != functions.end()) { return it->second; }
else if (parent) { return parent->getFunction(id); } else if (parent) { return parent->getFunction(id); }
else { return std::nullopt; } else
{
return std::nullopt;
}
} }
std::optional<FString> getFunctionName(std::size_t id) std::optional<FString> getFunctionName(std::size_t id)
{ {
auto it = functionNames.find(id); auto it = functionNames.find(id);
if (it != functionNames.end()) { return it->second; } if (it != functionNames.end()) { return it->second; }
else if (parent) { return parent->getFunctionName(id); } else if (parent) { return parent->getFunctionName(id); }
else { return std::nullopt; } else
{
return std::nullopt;
}
} }
// std::optional<FString> getStructName(std::size_t id) // std::optional<FString> getStructName(std::size_t id)
// { // {
@@ -188,24 +193,15 @@ namespace Fig
else if (parent != nullptr) { return parent->contains(name); } else if (parent != nullptr) { return parent->contains(name); }
return false; return false;
} }
bool containsInThisScope(const FString &name) const bool containsInThisScope(const FString &name) const { return variables.contains(name); }
{
return variables.contains(name);
}
TypeInfo getTypeInfo(const FString &name) TypeInfo getTypeInfo(const FString &name) { return get(name)->declaredType; }
{
return get(name)->declaredType;
}
bool isInFunctionContext() bool isInFunctionContext()
{ {
ContextPtr ctx = shared_from_this(); ContextPtr ctx = shared_from_this();
while (ctx) while (ctx)
{ {
if (ctx->getScopeName().find(u8"<Function ") == 0) if (ctx->getScopeName().find(u8"<Function ") == 0) { return true; }
{
return true;
}
ctx = ctx->parent; ctx = ctx->parent;
} }
return false; return false;
@@ -215,8 +211,7 @@ namespace Fig
ContextPtr ctx = shared_from_this(); ContextPtr ctx = shared_from_this();
while (ctx) while (ctx)
{ {
if (ctx->getScopeName().find(u8"<While ") == 0 if (ctx->getScopeName().find(u8"<While ") == 0 or ctx->getScopeName().find(u8"<For ") == 0)
or ctx->getScopeName().find(u8"<For ") == 0)
{ {
return true; return true;
} }
@@ -225,8 +220,7 @@ namespace Fig
return false; return false;
} }
bool hasImplRegisted(const TypeInfo &structType, bool hasImplRegisted(const TypeInfo &structType, const TypeInfo &interfaceType) const
const TypeInfo &interfaceType) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -239,9 +233,7 @@ namespace Fig
return parent && parent->hasImplRegisted(structType, interfaceType); return parent && parent->hasImplRegisted(structType, interfaceType);
} }
std::optional<ImplRecord> std::optional<ImplRecord> getImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType) const
getImplRecord(const TypeInfo &structType,
const TypeInfo &interfaceType) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -257,9 +249,7 @@ namespace Fig
return std::nullopt; return std::nullopt;
} }
void setImplRecord(const TypeInfo &structType, void setImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType, const ImplRecord &record)
const TypeInfo &interfaceType,
const ImplRecord &record)
{ {
auto &list = implRegistry[structType]; auto &list = implRegistry[structType];
@@ -271,8 +261,7 @@ namespace Fig
list.push_back(record); // order is the level list.push_back(record); // order is the level
} }
bool hasMethodImplemented(const TypeInfo &structType, bool hasMethodImplemented(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -283,19 +272,16 @@ namespace Fig
} }
} }
return parent return parent && parent->hasMethodImplemented(structType, functionName);
&& parent->hasMethodImplemented(structType, functionName);
} }
bool hasDefaultImplementedMethod(const TypeInfo &structType, bool hasDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it == implRegistry.end()) return false; if (it == implRegistry.end()) return false;
std::vector<TypeInfo> implementedInterfaces; std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second) for (auto &record : it->second) implementedInterfaces.push_back(record.interfaceType);
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables) for (auto &[_, slot] : variables)
{ {
@@ -303,25 +289,22 @@ namespace Fig
InterfaceType &interface = slot->value->as<InterfaceType>(); InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented = std::any_of( bool implemented = std::any_of(implementedInterfaces.begin(),
implementedInterfaces.begin(), implementedInterfaces.end(),
implementedInterfaces.end(), [&](const TypeInfo &ti) { return ti == interface.type; });
[&](const TypeInfo &ti) { return ti == interface.type; });
if (!implemented) continue; if (!implemented) continue;
for (auto &method : interface.methods) for (auto &method : interface.methods)
{ {
if (method.name == functionName && method.hasDefaultBody()) if (method.name == functionName && method.hasDefaultBody()) return true;
return true;
} }
} }
return false; return false;
} }
Function getDefaultImplementedMethod(const TypeInfo &structType, Ast::InterfaceMethod getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
const FString &functionName)
{ {
// O(N²) // O(N²)
// SLOW // SLOW
@@ -335,8 +318,7 @@ namespace Fig
if (it == implRegistry.end()) assert(false); if (it == implRegistry.end()) assert(false);
std::vector<TypeInfo> implementedInterfaces; std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second) for (auto &record : it->second) implementedInterfaces.push_back(record.interfaceType);
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables) for (auto &[_, slot] : variables)
{ {
@@ -344,10 +326,9 @@ namespace Fig
InterfaceType &interface = slot->value->as<InterfaceType>(); InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented = std::any_of( bool implemented = std::any_of(implementedInterfaces.begin(),
implementedInterfaces.begin(), implementedInterfaces.end(),
implementedInterfaces.end(), [&](const TypeInfo &ti) { return ti == interface.type; });
[&](const TypeInfo &ti) { return ti == interface.type; });
if (!implemented) continue; if (!implemented) continue;
@@ -356,21 +337,15 @@ namespace Fig
if (method.name == functionName) if (method.name == functionName)
{ {
if (!method.hasDefaultBody()) assert(false); if (!method.hasDefaultBody()) assert(false);
return method;
return Function(method.paras,
TypeInfo(method.returnType),
method.defaultBody,
shared_from_this());
} }
} }
} }
assert(false); assert(false);
return Function(); // ignore warning
} }
const Function &getImplementedMethod(const TypeInfo &structType, const Function &getImplementedMethod(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -382,11 +357,10 @@ namespace Fig
} }
} }
if (parent) if (parent) return parent->getImplementedMethod(structType, functionName);
return parent->getImplementedMethod(structType, functionName);
assert(false); // not found assert(false); // not found
throw ""; // ignore warning throw ""; // ignore warning
} }
void printStackTrace(std::ostream &os = std::cerr, int indent = 0) const void printStackTrace(std::ostream &os = std::cerr, int indent = 0) const
@@ -403,8 +377,7 @@ namespace Fig
os << "[STACK TRACE]\n"; os << "[STACK TRACE]\n";
for (int i = static_cast<int>(chain.size()) - 1; i >= 0; --i) for (int i = static_cast<int>(chain.size()) - 1; i >= 0; --i)
{ {
os << " #" << (chain.size() - 1 - i) << " " os << " #" << (chain.size() - 1 - i) << " " << chain[i]->scopeName.toBasicString() << "\n";
<< chain[i]->scopeName.toBasicString() << "\n";
} }
} }
}; };

View File

@@ -0,0 +1,40 @@
#pragma once
#include "Value/value.hpp"
#include <Core/fig_string.hpp>
#include <Value/value_forward.hpp>
#include <Value/Type.hpp>
#include <array>
#include <memory>
namespace Fig
{
class IntPool
{
private:
static constexpr ValueType::IntClass CACHE_MIN = -128;
static constexpr ValueType::IntClass CACHE_MAX = 127;
std::array<ObjectPtr, CACHE_MAX - CACHE_MIN + 1> cache;
public:
IntPool()
{
for (ValueType::IntClass i = CACHE_MIN; i <= CACHE_MAX; ++i)
{
cache[i - CACHE_MIN] = std::make_shared<Object>(i);
}
}
ObjectPtr createInt(ValueType::IntClass val) const
{
if (val >= CACHE_MIN && val <= CACHE_MAX) { return cache[val - CACHE_MIN]; }
return std::make_shared<Object>(val);
}
static const IntPool &getInstance()
{
static IntPool pool;
return pool;
}
};
}; // namespace Fig

View File

@@ -87,7 +87,7 @@ namespace Fig
std::format("Variable `{}` expects type `{}`, but got '{}'", std::format("Variable `{}` expects type `{}`, but got '{}'",
s->name.toBasicString(), s->name.toBasicString(),
s->declaredType.toString().toBasicString(), s->declaredType.toString().toBasicString(),
v->getTypeInfo().toString().toBasicString()))); prettyType(v).toBasicString())));
} }
if (isAccessConst(s->am)) if (isAccessConst(s->am))
{ {

View File

@@ -2,6 +2,7 @@
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <unordered_set>
#include <variant> #include <variant>
#include <map> #include <map>
@@ -75,6 +76,28 @@ namespace Fig
using BoolClass = bool; using BoolClass = bool;
using NullClass = std::monostate; using NullClass = std::monostate;
using StringClass = FString; using StringClass = FString;
static const std::unordered_set<TypeInfo, TypeInfoHash> builtinTypes
{
Any,
Null,
Int,
String,
Bool,
Double,
Function,
StructType,
StructInstance,
List,
Map,
Module,
InterfaceType
};
inline bool isTypeBuiltin(const TypeInfo &type)
{
return builtinTypes.contains(type);
}
}; // namespace ValueType }; // namespace ValueType
}; // namespace Fig }; // namespace Fig

View File

@@ -4,11 +4,12 @@
#include <Ast/AccessModifier.hpp> #include <Ast/AccessModifier.hpp>
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Value/Type.hpp> #include <Value/Type.hpp>
#include <Value/value_forward.hpp>
#include <memory> #include <memory>
namespace Fig namespace Fig
{ {
class Object;
using ObjectPtr = std::shared_ptr<Object>;
struct VariableSlot struct VariableSlot
{ {
FString name; FString name;

View File

@@ -1,3 +1,4 @@
#include "Value/structType.hpp"
#include <Value/Type.hpp> #include <Value/Type.hpp>
#include <Value/value.hpp> #include <Value/value.hpp>
#include <Context/context.hpp> #include <Context/context.hpp>
@@ -26,9 +27,7 @@ namespace Fig
{ {
if (!typeMap.contains(_name)) if (!typeMap.contains(_name))
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("No type named '{}'", _name.toBasicString())));
"No type named '{}'",
_name.toBasicString())));
// *this = ValueType::String; // *this = ValueType::String;
} }
id = typeMap.at(name); // may throw id = typeMap.at(name); // may throw
@@ -41,10 +40,7 @@ namespace Fig
ObjectPtr value = key.value; ObjectPtr value = key.value;
const TypeInfo &type = value->getTypeInfo(); const TypeInfo &type = value->getTypeInfo();
if (type == ValueType::Int) if (type == ValueType::Int) { return std::hash<ValueType::IntClass>{}(value->as<ValueType::IntClass>()); }
{
return std::hash<ValueType::IntClass>{}(value->as<ValueType::IntClass>());
}
if (type == ValueType::Double) if (type == ValueType::Double)
{ {
return std::hash<ValueType::DoubleClass>{}(value->as<ValueType::DoubleClass>()); return std::hash<ValueType::DoubleClass>{}(value->as<ValueType::DoubleClass>());
@@ -61,10 +57,7 @@ namespace Fig
{ {
auto HashFields = [](std::vector<Field> fields) { auto HashFields = [](std::vector<Field> fields) {
size_t r = 0; size_t r = 0;
for (auto &f : fields) for (auto &f : fields) { r += std::hash<Field>{}(f); }
{
r += std::hash<Field>{}(f);
}
return r; return r;
}; };
const StructType &st = value->as<StructType>(); const StructType &st = value->as<StructType>();
@@ -73,19 +66,30 @@ namespace Fig
if (type == ValueType::StructInstance) if (type == ValueType::StructInstance)
{ {
const StructInstance &si = value->as<StructInstance>(); const StructInstance &si = value->as<StructInstance>();
return std::hash<TypeInfo>{}(si.parentType) + std::hash<uint64_t>{}(reinterpret_cast<uint64_t>(std::addressof(*si.localContext))); return std::hash<TypeInfo>{}(si.parentType)
+ std::hash<uint64_t>{}(reinterpret_cast<uint64_t>(std::addressof(*si.localContext)));
} }
assert(false); assert(false);
throw ""; // ignore warning throw ""; // ignore warning
} }
} }
FString prettyType(std::shared_ptr<const Object> obj) TypeInfo actualType(std::shared_ptr<const Object> obj)
{ {
auto t = obj->getTypeInfo(); auto t = obj->getTypeInfo();
if (t == ValueType::StructInstance)
return obj->as<StructInstance>().parentType.toString(); // dispatch builtin struct types (like Int{}, List{} e.g...)
return t.toString(); if (t == ValueType::StructType)
{
return obj->as<StructType>().type;
}
if (t == ValueType::StructInstance) return obj->as<StructInstance>().parentType;
return t;
}
FString prettyType(std::shared_ptr<const Object> obj)
{
return actualType(obj).toString();
} }
const TypeInfo ValueType::Any(FString(u8"Any"), true); // id: 1 const TypeInfo ValueType::Any(FString(u8"Any"), true); // id: 1
@@ -102,8 +106,6 @@ namespace Fig
const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12 const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12
const TypeInfo ValueType::InterfaceType(FString(u8"InterfaceType"), true); // id: 13 const TypeInfo ValueType::InterfaceType(FString(u8"InterfaceType"), true); // id: 13
bool implements(const TypeInfo &structType, const TypeInfo &interfaceType, ContextPtr ctx) bool implements(const TypeInfo &structType, const TypeInfo &interfaceType, ContextPtr ctx)
{ {
return ctx->hasImplRegisted(structType, interfaceType); return ctx->hasImplRegisted(structType, interfaceType);
@@ -111,28 +113,25 @@ namespace Fig
bool isTypeMatch(const TypeInfo &expected, ObjectPtr obj, ContextPtr ctx) bool isTypeMatch(const TypeInfo &expected, ObjectPtr obj, ContextPtr ctx)
{ {
if (expected == ValueType::Any) if (expected == ValueType::Any) return true;
return true;
TypeInfo actual = obj->getTypeInfo(); TypeInfo actual = obj->getTypeInfo();
if (obj->is<StructInstance>()) if (obj->is<StructType>())
{
const StructType &t = obj->as<StructType>();
if (expected == t.type) // the StructType typeinfo
{
return true;
}
}
else if (obj->is<StructInstance>())
{ {
const StructInstance &si = obj->as<StructInstance>(); const StructInstance &si = obj->as<StructInstance>();
if (si.parentType == expected) if (si.parentType == expected) { return true; }
{ if (implements(si.parentType, expected, ctx)) { return true; }
return true;
}
if (implements(si.parentType, expected, ctx))
{
return true;
}
return false;
}
else
{
return expected == actual;
} }
return expected == actual;
} }
} // namespace Fig } // namespace Fig

View File

@@ -6,6 +6,7 @@
#include <Value/Type.hpp> #include <Value/Type.hpp>
#include <Value/valueError.hpp> #include <Value/valueError.hpp>
#include <Value/module.hpp> #include <Value/module.hpp>
#include <Value/value_forward.hpp>
#include <memory> #include <memory>
#include <variant> #include <variant>
@@ -31,10 +32,8 @@ namespace Fig
static_cast<ValueType::DoubleClass>(std::numeric_limits<ValueType::IntClass>::min()); static_cast<ValueType::DoubleClass>(std::numeric_limits<ValueType::IntClass>::min());
return d > intMaxAsDouble || d < intMinAsDouble; return d > intMaxAsDouble || d < intMinAsDouble;
} }
class Object;
using ObjectPtr = std::shared_ptr<Object>;
TypeInfo actualType(std::shared_ptr<const Object> obj);
FString prettyType(std::shared_ptr<const Object> obj); FString prettyType(std::shared_ptr<const Object> obj);
bool operator==(const Object &, const Object &); bool operator==(const Object &, const Object &);
@@ -509,7 +508,7 @@ namespace Fig
{ {
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>(); bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = lhs.getNumericValue() + rhs.getNumericValue(); auto result = lhs.getNumericValue() + rhs.getNumericValue();
if (bothInt && !isNumberExceededIntLimit(result)) if (bothInt)
return Object(static_cast<ValueType::IntClass>(result)); return Object(static_cast<ValueType::IntClass>(result));
return Object(result); return Object(result);
} }
@@ -526,7 +525,7 @@ namespace Fig
{ {
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>(); bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = lhs.getNumericValue() - rhs.getNumericValue(); auto result = lhs.getNumericValue() - rhs.getNumericValue();
if (bothInt && !isNumberExceededIntLimit(result)) if (bothInt)
return Object(static_cast<ValueType::IntClass>(result)); return Object(static_cast<ValueType::IntClass>(result));
return Object(result); return Object(result);
} }
@@ -541,10 +540,20 @@ namespace Fig
{ {
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>(); bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = lhs.getNumericValue() * rhs.getNumericValue(); auto result = lhs.getNumericValue() * rhs.getNumericValue();
if (bothInt && !isNumberExceededIntLimit(result)) if (bothInt)
return Object(static_cast<ValueType::IntClass>(result)); return Object(static_cast<ValueType::IntClass>(result));
return Object(result); return Object(result);
} }
if (lhs.is<ValueType::StringClass>() && rhs.is<ValueType::IntClass>())
{
FString result;
const FString &l = lhs.as<ValueType::StringClass>();
for (size_t i=0; i < rhs.getNumericValue(); ++i)
{
result += l;
}
return Object(result);
}
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs)));
} }
@@ -557,10 +566,13 @@ namespace Fig
auto rnv = rhs.getNumericValue(); auto rnv = rhs.getNumericValue();
if (rnv == 0) if (rnv == 0)
throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs)));
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>(); // bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = lhs.getNumericValue() / rnv; auto result = lhs.getNumericValue() / rnv;
if (bothInt && !isNumberExceededIntLimit(result)) // if (bothInt)
return Object(static_cast<ValueType::IntClass>(result)); // return Object(static_cast<ValueType::IntClass>(result));
// int / int maybe decimals
// DO NOT convert it to INT
return Object(result); return Object(result);
} }
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs)));
@@ -570,15 +582,24 @@ namespace Fig
{ {
if (lhs.isNull() || rhs.isNull()) if (lhs.isNull() || rhs.isNull())
throw ValueError(FString(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs)));
if (lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>())
{
ValueType::IntClass lv = lhs.as<ValueType::IntClass>();
ValueType::IntClass rv = lhs.as<ValueType::IntClass>();
if (rv == 0) throw ValueError(FString(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
ValueType::IntClass q = lv / rv;
ValueType::IntClass r = lv % rv;
if (r != 0 && ((lv < 0) != (rv < 0))) { q -= 1; }
return q;
}
if (lhs.isNumeric() && rhs.isNumeric()) if (lhs.isNumeric() && rhs.isNumeric())
{ {
auto rnv = rhs.getNumericValue(); auto rnv = rhs.getNumericValue();
if (rnv == 0) if (rnv == 0)
throw ValueError(FString(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = std::fmod(lhs.getNumericValue(), rnv); auto result = std::fmod(lhs.getNumericValue(), rnv);
if (bothInt && !isNumberExceededIntLimit(result))
return Object(static_cast<ValueType::IntClass>(result));
return Object(result); return Object(result);
} }
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs)));
@@ -695,7 +716,7 @@ namespace Fig
{ {
bool bothInt = base.is<ValueType::IntClass>() && exp.is<ValueType::IntClass>(); bool bothInt = base.is<ValueType::IntClass>() && exp.is<ValueType::IntClass>();
auto result = std::pow(base.getNumericValue(), exp.getNumericValue()); auto result = std::pow(base.getNumericValue(), exp.getNumericValue());
if (bothInt && !isNumberExceededIntLimit(result)) if (bothInt)
return Object(static_cast<ValueType::IntClass>(result)); return Object(static_cast<ValueType::IntClass>(result));
return Object(result); return Object(result);
} }
@@ -703,7 +724,6 @@ namespace Fig
} }
}; };
using ObjectPtr = std::shared_ptr<Object>;
using RvObject = ObjectPtr; using RvObject = ObjectPtr;
inline bool operator==(const ValueKey &l, const ValueKey &r) inline bool operator==(const ValueKey &l, const ValueKey &r)

View File

@@ -0,0 +1,10 @@
#pragma once
#include <memory>
namespace Fig
{
class Object;
using ObjectPtr = std::shared_ptr<Object>;
}; // namespace Fig

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#include "Ast/Statements/ImplementSt.hpp" #include "Ast/Expressions/InitExpr.hpp"
#include "Ast/Statements/InterfaceDefSt.hpp" #include <Ast/Statements/ImplementSt.hpp>
#include "Value/Type.hpp" #include <Ast/Statements/InterfaceDefSt.hpp>
#include <Value/Type.hpp>
#include <Ast/ast.hpp> #include <Ast/ast.hpp>
#include <Context/context.hpp> #include <Context/context.hpp>
@@ -63,12 +64,18 @@ namespace Fig
public: public:
FString sourcePath; FString sourcePath;
std::vector<FString> sourceLines;
void SetSourcePath(const FString &sp) void SetSourcePath(const FString &sp)
{ {
sourcePath = sp; sourcePath = sp;
} }
void SetSourceLines(const std::vector<FString> &sl)
{
sourceLines = sl;
}
void SetGlobalContext(ContextPtr ctx) void SetGlobalContext(ContextPtr ctx)
{ {
assert(ctx != nullptr); assert(ctx != nullptr);
@@ -121,7 +128,7 @@ namespace Fig
LvObject evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b] LvObject evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b]
/* Right-value eval*/ /* Right-value eval*/
RvObject evalInitExpr(Ast::InitExpr, ContextPtr); // only allows evalUnary to call
RvObject evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *.... RvObject evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *....
RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr

View File

@@ -10,7 +10,10 @@ namespace Fig
public: public:
FString typeName; FString typeName;
using AddressableError::AddressableError; using AddressableError::AddressableError;
EvaluatorError(FString _typeName, FString msg, Ast::AstBase ast, std::source_location loc = std::source_location::current()) EvaluatorError(FString _typeName,
FString msg,
Ast::AstBase ast,
std::source_location loc = std::source_location::current())
{ {
message = msg; message = msg;
line = ast->getAAI().line; line = ast->getAAI().line;
@@ -20,8 +23,13 @@ namespace Fig
typeName = std::move(_typeName); typeName = std::move(_typeName);
sourcePath = *ast->getAAI().sourcePath;
sourceLines = *ast->getAAI().sourceLines;
} }
EvaluatorError(FString _typeName, std::string_view msg, Ast::AstBase ast, std::source_location loc = std::source_location::current()) EvaluatorError(FString _typeName,
std::string_view msg,
Ast::AstBase ast,
std::source_location loc = std::source_location::current())
{ {
message = FString::fromBasicString(std::string(msg.data())); message = FString::fromBasicString(std::string(msg.data()));
line = ast->getAAI().line; line = ast->getAAI().line;
@@ -30,13 +38,11 @@ namespace Fig
src_loc = std::move(loc); src_loc = std::move(loc);
typeName = std::move(_typeName); typeName = std::move(_typeName);
sourcePath = *ast->getAAI().sourcePath;
sourceLines = *ast->getAAI().sourceLines;
} }
virtual FString getErrorType() const override virtual FString getErrorType() const override { return typeName; }
{
return typeName;
}
}; };
}; }; // namespace Fig

View File

@@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
*/ */
#include <Utils/argparse/argparse.hpp> #include <Utils/argparse/argparse.hpp>
#include <print> // #include <print>
#include <fstream> #include <fstream>
#include <Core/core.hpp> #include <Core/core.hpp>
@@ -38,6 +38,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
#include <Utils/AstPrinter.hpp> #include <Utils/AstPrinter.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#include <Error/errorLog.hpp> #include <Error/errorLog.hpp>
#include <Core/runtimeTime.hpp>
static size_t addressableErrorCount = 0; static size_t addressableErrorCount = 0;
static size_t unaddressableErrorCount = 0; static size_t unaddressableErrorCount = 0;
@@ -45,6 +46,10 @@ static size_t unaddressableErrorCount = 0;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
Time::init();
// init, set start_time (std::chrono::time_point)
argparse::ArgumentParser program("Fig Interpreter", Fig::Core::VERSION.data()); argparse::ArgumentParser program("Fig Interpreter", Fig::Core::VERSION.data());
program.add_argument("source") program.add_argument("source")
.help("source file to be interpreted") .help("source file to be interpreted")
@@ -84,7 +89,9 @@ int main(int argc, char **argv)
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close(); file.close();
Fig::Lexer lexer((Fig::FString(source))); std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
Fig::Lexer lexer((Fig::FString(source)), sourcePath, sourceLines);
// Token tok; // Token tok;
// while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile) // while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile)
@@ -92,11 +99,9 @@ int main(int argc, char **argv)
// std::println("{}", tok.toString().toBasicString()); // std::println("{}", tok.toString().toBasicString());
// } // }
Fig::Parser parser(lexer); Fig::Parser parser(lexer, sourcePath, sourceLines);
std::vector<Fig::Ast::AstBase> asts; std::vector<Fig::Ast::AstBase> asts;
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
try try
{ {
asts = parser.parseAll(); asts = parser.parseAll();
@@ -104,7 +109,7 @@ int main(int argc, char **argv)
catch (const Fig::AddressableError &e) catch (const Fig::AddressableError &e)
{ {
addressableErrorCount++; addressableErrorCount++;
ErrorLog::logAddressableError(e, sourcePath, sourceLines); ErrorLog::logAddressableError(e);
return 1; return 1;
} }
catch (const Fig::UnaddressableError &e) catch (const Fig::UnaddressableError &e)
@@ -129,6 +134,7 @@ int main(int argc, char **argv)
Fig::Evaluator evaluator; Fig::Evaluator evaluator;
evaluator.SetSourcePath(sourcePath); evaluator.SetSourcePath(sourcePath);
evaluator.SetSourceLines(sourceLines);
evaluator.CreateGlobalContext(); evaluator.CreateGlobalContext();
evaluator.RegisterBuiltinsValue(); evaluator.RegisterBuiltinsValue();
@@ -139,7 +145,7 @@ int main(int argc, char **argv)
catch (const Fig::AddressableError &e) catch (const Fig::AddressableError &e)
{ {
addressableErrorCount++; addressableErrorCount++;
ErrorLog::logAddressableError(e, sourcePath, sourceLines); ErrorLog::logAddressableError(e);
evaluator.printStackTrace(); evaluator.printStackTrace();
return 1; return 1;
} }

View File

@@ -6,6 +6,14 @@
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#if 0
#include <iostream> // debug
#endif
#ifndef SourceInfo
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
#endif
namespace Fig namespace Fig
{ {
@@ -58,7 +66,10 @@ namespace Fig
{FString(u8"["), TokenType::LeftBracket}, {FString(u8"["), TokenType::LeftBracket},
{FString(u8"]"), TokenType::RightBracket}, {FString(u8"]"), TokenType::RightBracket},
{FString(u8"{"), TokenType::LeftBrace}, {FString(u8"{"), TokenType::LeftBrace},
{FString(u8"}"), TokenType::RightBrace}}; {FString(u8"}"), TokenType::RightBrace},
{FString(u8"?"), TokenType::Question},
{FString(u8"!"), TokenType::Not},
};
const std::unordered_map<FString, TokenType> Lexer::keyword_map{ const std::unordered_map<FString, TokenType> Lexer::keyword_map{
{FString(u8"and"), TokenType::And}, {FString(u8"and"), TokenType::And},
@@ -73,6 +84,7 @@ namespace Fig
{FString(u8"for"), TokenType::For}, {FString(u8"for"), TokenType::For},
{FString(u8"if"), TokenType::If}, {FString(u8"if"), TokenType::If},
{FString(u8"else"), TokenType::Else}, {FString(u8"else"), TokenType::Else},
{FString(u8"new"), TokenType::New},
{FString(u8"struct"), TokenType::Struct}, {FString(u8"struct"), TokenType::Struct},
{FString(u8"interface"), TokenType::Interface}, {FString(u8"interface"), TokenType::Interface},
{FString(u8"impl"), TokenType::Implement}, {FString(u8"impl"), TokenType::Implement},
@@ -159,7 +171,7 @@ namespace Fig
{ {
if (it.isEnd()) if (it.isEnd())
{ {
error = SyntaxError(u8"Unterminated FString", this->line, it.column()); error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
next(); next();
@@ -196,12 +208,11 @@ namespace Fig
} }
else else
{ {
error = SyntaxError(FString( error = SyntaxError(FString(std::format("Unsupported escape character: {}",
std::format( FString(ec.getString()).toBasicString())),
"Unsupported escape character: {}",
FString(ec.getString()).toBasicString())),
this->line, this->line,
it.column()); it.column(),
SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
} }
@@ -213,7 +224,7 @@ namespace Fig
} }
if (unterminated) if (unterminated)
{ {
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col); error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
return Token(str, TokenType::LiteralString); return Token(str, TokenType::LiteralString);
@@ -240,7 +251,7 @@ namespace Fig
} }
if (unterminated) if (unterminated)
{ {
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col); error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
return Token(str, TokenType::LiteralString); return Token(str, TokenType::LiteralString);
@@ -271,7 +282,7 @@ namespace Fig
{ {
if (it.isEnd()) if (it.isEnd())
{ {
error = SyntaxError(u8"Unterminated FString", this->line, it.column()); error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
next(); next();
@@ -313,12 +324,11 @@ namespace Fig
} }
else else
{ {
error = SyntaxError(FString( error = SyntaxError(FString(std::format("Unsupported escape character: {}",
std::format( FString(ec.getString()).toBasicString())),
"Unsupported escape character: {}",
FString(ec.getString()).toBasicString())),
this->line, this->line,
it.column()); it.column(),
SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
} }
@@ -330,7 +340,7 @@ namespace Fig
} }
if (unterminated) if (unterminated)
{ {
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col); error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
return Token(str, TokenType::LiteralString); return Token(str, TokenType::LiteralString);
@@ -339,21 +349,27 @@ namespace Fig
{ {
FString numStr; FString numStr;
bool hasPoint = false; bool hasPoint = false;
// 负号(减号) 直接交由 scanSymbol处理在parser中被分类->与数字结合/变为操作数
while (hasNext()) while (hasNext())
{ {
UTF8Char ch = *it; UTF8Char ch = *it;
if (ch.isDigit() or ch == U'e') // . / e / - for scientific counting
if (ch.isDigit() || ch == U'e')
{ {
numStr += ch.getString(); numStr += ch.getString();
next(); next();
} }
else if (ch == U'-' and numStr.ends_with(U'-')) else if (ch == U'-' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
{ {
numStr += ch.getString(); numStr += ch.getString();
next(); next();
} }
else if (ch == U'.' and not hasPoint) else if (ch == U'+' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
{
numStr += ch.getString();
next();
}
else if (ch == U'.' && !hasPoint)
{ {
hasPoint = true; hasPoint = true;
numStr += ch.getString(); numStr += ch.getString();
@@ -364,22 +380,93 @@ namespace Fig
break; break;
} }
} }
// Numbers in Fig-lang if (numStr.empty()) { return IllegalTok; }
/*
114514 if (numStr.ends_with(U'e'))
1145.14
1.14e3 -> 1140
1.14e-3 -> 0.00114
.3 -> 0.3
*/
// checking legality
if ((*numStr.end()) == u'e') // e 后面必须跟整数表示科学计数
{ {
error = SyntaxError(FString( error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
std::format("Ellegal number literal: {}", numStr.toBasicString())), this->line,
this->line, it.column()); it.column(),
SourceInfo(this));
return IllegalTok; return IllegalTok;
} }
bool hasDigit = false;
for (auto it = numStr.begin(); it != numStr.end(); ++it)
{
if (isdigit(*it))
{
hasDigit = true;
break;
}
}
if (!hasDigit)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
size_t ePos = numStr.find(U'e');
if (ePos != FString::npos)
{
if (ePos == 0)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
if (ePos + 1 >= numStr.length())
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
bool hasDigitAfterE = false;
for (size_t i = ePos + 1; i < numStr.length(); ++i)
{
UTF8Char c = std::u8string(1,numStr[i]);
if (c == U'+' || c == U'-')
{
if (i != ePos + 1)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
continue;
}
if (c.isDigit()) { hasDigitAfterE = true; }
else
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
}
if (!hasDigitAfterE)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column(),
SourceInfo(this));
return IllegalTok;
}
}
return Token(numStr, TokenType::LiteralNumber); return Token(numStr, TokenType::LiteralNumber);
} }
Token Lexer::scanSymbol() Token Lexer::scanSymbol()
@@ -400,9 +487,10 @@ namespace Fig
if (!startsWith(sym)) if (!startsWith(sym))
{ {
error = SyntaxError( error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
FString(std::format("No such operator: {}", sym.toBasicString())), this->line,
this->line, it.column()); it.column(),
SourceInfo(this));
next(); next();
return IllegalTok; return IllegalTok;
} }
@@ -428,13 +516,14 @@ namespace Fig
if (!symbol_map.contains(sym)) if (!symbol_map.contains(sym))
{ {
error = SyntaxError( error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
FString(std::format("No such operator: {}", sym.toBasicString())), this->line,
this->line, it.column()); it.column(),
SourceInfo(this));
next(); next();
return IllegalTok; return IllegalTok;
} }
// std::cerr << Token(sym, symbol_map.at(sym)).toString().toBasicString() << '\n;
next(); next();
return Token(sym, symbol_map.at(sym)); return Token(sym, symbol_map.at(sym));
} }
@@ -490,7 +579,8 @@ namespace Fig
if (!terminated) if (!terminated)
{ {
error = SyntaxError(FString(u8"Unterminated multiline comment"), this->line, it.column()); error =
SyntaxError(FString(u8"Unterminated multiline comment"), this->line, it.column(), SourceInfo(this));
next(); next();
return IllegalTok; return IllegalTok;
} }
@@ -522,13 +612,13 @@ namespace Fig
if (!hasNext()) if (!hasNext())
{ {
next(); next();
// return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column); return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
} }
c = it.peek(); c = it.peek();
if (c != U'/' and c != U'*') if (c != U'/' and c != U'*')
{ {
next(); next();
// return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column); return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
} }
scanComments().setPos(last_line, last_column); scanComments().setPos(last_line, last_column);
return nextToken(); return nextToken();
@@ -561,9 +651,11 @@ namespace Fig
} }
else else
{ {
error = SyntaxError(FString( error =
std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())), SyntaxError(FString(std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
this->line, it.column()); this->line,
it.column(),
SourceInfo(this));
if (hasNext()) if (hasNext())
{ {
next(); next();

View File

@@ -23,6 +23,9 @@ namespace Fig
SyntaxError error; SyntaxError error;
UTF8Iterator it; UTF8Iterator it;
FString sourcePath;
std::vector<FString> sourceLines;
std::vector<Warning> warnings; std::vector<Warning> warnings;
size_t last_line, last_column, column = 1; size_t last_line, last_column, column = 1;
@@ -60,8 +63,8 @@ namespace Fig
static const std::unordered_map<FString, TokenType> symbol_map; static const std::unordered_map<FString, TokenType> symbol_map;
static const std::unordered_map<FString, TokenType> keyword_map; static const std::unordered_map<FString, TokenType> keyword_map;
inline Lexer(const FString &_source) : inline Lexer(const FString &_source, const FString &_sourcePath, const std::vector<FString> &_sourceLines) :
source(_source), it(source) source(_source), it(source), sourcePath(_sourcePath), sourceLines(_sourceLines)
{ {
line = 1; line = 1;
} }

View File

@@ -7,17 +7,40 @@
import std.value; // `type` function and string_from import std.value; // `type` function and string_from
struct FormatError
{
public msg: String;
}
impl Error for FormatError
{
getErrorClass()
{
return "FormatError";
}
getErrorMessage()
{
return getErrorClass() + ": " + msg;
}
toString()
{
return getErrorMessage();
}
}
public func format(objects ...) -> Any public func format(objects ...) -> Any
{ {
if objects.length() < 1 if objects.length() < 1
{ {
return null; throw new FormatError{"Require format string"};
} }
var fmt := objects[0]; var fmt := objects[0];
if value.type(fmt) != "String" var fmtType := value.type(fmt);
if fmtType != "String"
{ {
return null; throw new FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
} }
var result := ""; var result := "";
@@ -33,7 +56,7 @@ public func format(objects ...) -> Any
{ {
if (i + 1 >= length) if (i + 1 >= length)
{ {
return null; throw new FormatError{"unclosed brace"};
} }
var nextChar = fmt[i + 1]; var nextChar = fmt[i + 1];
@@ -57,12 +80,12 @@ public func format(objects ...) -> Any
if endIndex == -1 if endIndex == -1
{ {
return null; throw new FormatError{"unclosed brace"};
} }
if argIndex >= objects.length() if argIndex >= objects.length()
{ {
return null; throw new FormatError{"require enough format expression"};
} }
result += value.string_from(objects[argIndex]); result += value.string_from(objects[argIndex]);
@@ -79,7 +102,7 @@ public func format(objects ...) -> Any
continue; continue;
} }
return null; throw new FormatError{"invalid format syntax"};
} }
else else
{ {
@@ -97,15 +120,16 @@ public func formatByListArgs(objects) -> Any
{ {
return null; return null;
} }
if objects.length() < 1 if objects.length() < 1
{ {
return null; throw new FormatError{"Require format string"};
} }
var fmt := objects[0]; var fmt := objects[0];
if value.type(fmt) != "String" var fmtType := value.type(fmt);
if fmtType != "String"
{ {
return null; throw new FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
} }
var result := ""; var result := "";
@@ -121,7 +145,7 @@ public func formatByListArgs(objects) -> Any
{ {
if (i + 1 >= length) if (i + 1 >= length)
{ {
return null; throw new FormatError{"unclosed brace"};
} }
var nextChar = fmt[i + 1]; var nextChar = fmt[i + 1];
@@ -145,12 +169,12 @@ public func formatByListArgs(objects) -> Any
if endIndex == -1 if endIndex == -1
{ {
return null; throw new FormatError{"unclosed brace"};
} }
if argIndex >= objects.length() if argIndex >= objects.length()
{ {
return null; throw new FormatError{"require enough format expression"};
} }
result += value.string_from(objects[argIndex]); result += value.string_from(objects[argIndex]);
@@ -167,7 +191,7 @@ public func formatByListArgs(objects) -> Any
continue; continue;
} }
return null; throw new FormatError{"invalid format syntax"};
} }
else else
{ {

View File

@@ -43,7 +43,8 @@ public func println(objects...) -> Int
public func printf(objects...) -> Any public func printf(objects...) -> Any
{ {
__fstdout_print(formater.formatByListArgs(objects)); var result := formater.formatByListArgs(objects);
__fstdout_print(result);
} }
// inputs // inputs

View File

@@ -0,0 +1,51 @@
/*
Official Module `time`
Library/time/time.fig
Copyright © 2026 PuqiAR. All rights reserved.
*/
import _builtins; // provides __ftime_now_ns (int64_t)
public struct Time
{
ns: Int; // int64_t, private
public func toNanos() -> Int
{
return ns;
}
public func toMicros() -> Int
{
return __fvalue_int_from(ns / 1000); // convert double to int
}
public func toMillis() -> Double
{
return ns / 1000 / 1000;
}
public func toSeconds() -> Double
{
return ns / 1000 / 1000 / 1000;
}
public func since(other: Time) -> Int
{
const time_ns := other.toNanos();
const result := ns - time_ns;
if result < 0
{
throw "time has been reversed! 😢";
}
return result;
}
// TODO: support `-` operator when Fig supports overload
}
public func now() -> Time
{
return new Time{__ftime_now_ns()};
}

View File

@@ -1,10 +1,15 @@
#pragma once #pragma once
#include "Ast/Statements/InterfaceDefSt.hpp" #include "Ast/Expressions/VarExpr.hpp"
#include "Ast/functionParameters.hpp" #include "Ast/Statements/VarDef.hpp"
#include "Ast/astBase.hpp"
#include <Ast/Statements/InterfaceDefSt.hpp>
#include <Ast/functionParameters.hpp>
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Value/value.hpp> #include <Value/value.hpp>
#include <Core/runtimeTime.hpp>
#include <chrono>
#include <numeric> #include <numeric>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
@@ -33,11 +38,19 @@ namespace Fig
{u8"true", Object::getTrueInstance()}, {u8"true", Object::getTrueInstance()},
{u8"false", Object::getFalseInstance()}, {u8"false", Object::getFalseInstance()},
{u8"Error", {u8"Error",
std::make_shared<Object>(InterfaceType( std::make_shared<Object>(InterfaceType(ErrorInterfaceTypeInfo,
ErrorInterfaceTypeInfo, {Ast::InterfaceMethod(u8"toString",
{Ast::InterfaceMethod(u8"toString", Ast::FunctionParameters({}, {}), u8"String", nullptr), Ast::FunctionParameters({}, {}),
Ast::InterfaceMethod(u8"getErrorClass", Ast::FunctionParameters({}, {}), u8"String", nullptr), std::make_shared<Ast::VarExprAst>(u8"String"),
Ast::InterfaceMethod(u8"getErrorMessage", Ast::FunctionParameters({}, {}), u8"String", nullptr)}))}, nullptr),
Ast::InterfaceMethod(u8"getErrorClass",
Ast::FunctionParameters({}, {}),
std::make_shared<Ast::VarExprAst>(u8"String"),
nullptr),
Ast::InterfaceMethod(u8"getErrorMessage",
Ast::FunctionParameters({}, {}),
std::make_shared<Ast::VarExprAst>(u8"String"),
nullptr)}))},
{u8"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))}, {u8"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
{u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))}, {u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
@@ -65,6 +78,7 @@ namespace Fig
{u8"__fvalue_double_parse", 1}, {u8"__fvalue_double_parse", 1},
{u8"__fvalue_double_from", 1}, {u8"__fvalue_double_from", 1},
{u8"__fvalue_string_from", 1}, {u8"__fvalue_string_from", 1},
{u8"__ftime_now_ns", 0},
/* math start */ /* math start */
{u8"__fmath_acos", 1}, {u8"__fmath_acos", 1},
{u8"__fmath_acosh", 1}, {u8"__fmath_acosh", 1},
@@ -194,6 +208,15 @@ namespace Fig
ObjectPtr val = args[0]; ObjectPtr val = args[0];
return std::make_shared<Object>(val->toStringIO()); return std::make_shared<Object>(val->toStringIO());
}}, }},
{u8"__ftime_now_ns",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
// returns nanoseconds
using namespace Fig::Time;
auto now = Clock::now();
return std::make_shared<Object>(static_cast<ValueType::IntClass>(
std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time).count()));
}},
/* math start */ /* math start */
{u8"__fmath_acos", {u8"__fmath_acos",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr { [](const std::vector<ObjectPtr> &args) -> ObjectPtr {

View File

@@ -1,9 +1,9 @@
#include "Ast/Statements/ErrorFlow.hpp" #include <Ast/Statements/ErrorFlow.hpp>
#include "Ast/Statements/ImplementSt.hpp" #include <Ast/Statements/ImplementSt.hpp>
#include "Ast/astBase.hpp" #include <Ast/astBase.hpp>
#include "Ast/functionParameters.hpp" #include <Ast/functionParameters.hpp>
#include "Error/error.hpp" #include <Error/error.hpp>
#include "Token/token.hpp" #include <Token/token.hpp>
#include <Parser/parser.hpp> #include <Parser/parser.hpp>
namespace Fig namespace Fig
@@ -22,7 +22,7 @@ namespace Fig
// 逻辑 // 逻辑
{Ast::Operator::And, {5, 6}}, {Ast::Operator::And, {5, 6}},
{Ast::Operator::Or, {4, 5}}, {Ast::Operator::Or, {4, 5}},
{Ast::Operator::Not, {30, 31}}, // 一元 // {Ast::Operator::Not, {30, 31}}, // 一元
// 比较 // 比较
{Ast::Operator::Equal, {7, 8}}, {Ast::Operator::Equal, {7, 8}},
@@ -37,7 +37,7 @@ namespace Fig
{Ast::Operator::BitAnd, {6, 7}}, {Ast::Operator::BitAnd, {6, 7}},
{Ast::Operator::BitOr, {4, 5}}, {Ast::Operator::BitOr, {4, 5}},
{Ast::Operator::BitXor, {5, 6}}, {Ast::Operator::BitXor, {5, 6}},
{Ast::Operator::BitNot, {30, 31}}, // 一元 // {Ast::Operator::BitNot, {30, 31}}, // 一元
{Ast::Operator::ShiftLeft, {15, 16}}, {Ast::Operator::ShiftLeft, {15, 16}},
{Ast::Operator::ShiftRight, {15, 16}}, {Ast::Operator::ShiftRight, {15, 16}},
@@ -54,6 +54,14 @@ namespace Fig
// // 点运算符 // // 点运算符
// {Ast::Operator::Dot, {40, 41}}, // {Ast::Operator::Dot, {40, 41}},
{Ast::Operator::TernaryCond, {3, 2}},
};
const std::unordered_map<Ast::Operator, Parser::Precedence> Parser::unaryOpPrecedence = {
{Ast::Operator::Subtract, 150}, // -
{Ast::Operator::BitAnd, 150}, // &
{Ast::Operator::BitNot, 150}, // ~
{Ast::Operator::Not, 150}, // !
}; };
Ast::VarDef Parser::__parseVarDef(bool isPublic) Ast::VarDef Parser::__parseVarDef(bool isPublic)
@@ -64,31 +72,31 @@ namespace Fig
expect(TokenType::Identifier); expect(TokenType::Identifier);
FString name = currentToken().getValue(); FString name = currentToken().getValue();
next(); next();
FString tiName = ValueType::Any.name; Ast::Expression declaredType = nullptr;
bool hasSpecificType = false; bool hasSpecificType = false;
if (isThis(TokenType::Colon)) // : if (isThis(TokenType::Colon)) // :
{ {
expectPeek(TokenType::Identifier, FString(u8"Type name")); next(); // consume `:`
next(); declaredType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
tiName = currentToken().getValue();
next();
hasSpecificType = true; hasSpecificType = true;
} }
if (isThis(TokenType::Semicolon)) if (isThis(TokenType::Semicolon))
{ {
next(); // consume `;`, no using expectConsume here cause we don't need to check again next(); // consume `;`, no using expectConsume here cause we don't need to check again
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, nullptr); return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, nullptr, false);
} }
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus"); if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
bool followupType = false;
if (isThis(TokenType::Walrus)) if (isThis(TokenType::Walrus))
{ {
if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8"")); if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
tiName = Parser::varDefTypeFollowed; followupType = true;
} }
next(); next();
Ast::Expression exp = parseExpression(0); Ast::Expression exp = parseExpression(0);
expectSemicolon(); expectSemicolon();
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, exp); return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, exp, followupType);
} }
ObjectPtr Parser::__parseValue() ObjectPtr Parser::__parseValue()
@@ -125,18 +133,12 @@ namespace Fig
return std::make_shared<Object>(i); return std::make_shared<Object>(i);
} }
} }
else if (currentToken().getType() == TokenType::LiteralString) else if (currentToken().getType() == TokenType::LiteralString) { return std::make_shared<Object>(_val); }
{
return std::make_shared<Object>(_val);
}
else if (currentToken().getType() == TokenType::LiteralBool) else if (currentToken().getType() == TokenType::LiteralBool)
{ {
return std::make_shared<Object>((_val == u8"true" ? true : false)); return std::make_shared<Object>((_val == u8"true" ? true : false));
} }
else if (currentToken().getType() == TokenType::LiteralNull) else if (currentToken().getType() == TokenType::LiteralNull) { return Object::getNullInstance(); }
{
return Object::getNullInstance();
}
else else
{ {
throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__)); throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__));
@@ -206,7 +208,7 @@ namespace Fig
variaPara = pname; variaPara = pname;
next(); // skip `...` next(); // skip `...`
if (!isThis(TokenType::RightParen)) if (!isThis(TokenType::RightParen))
throw SyntaxError( throwAddressableError<SyntaxError>(
u8"Expects right paren, variable parameter function can only have one parameter", u8"Expects right paren, variable parameter function can only have one parameter",
currentAAI.line, currentAAI.line,
currentAAI.column); currentAAI.column);
@@ -229,17 +231,17 @@ namespace Fig
next(); next();
expect(TokenType::LeftParen); expect(TokenType::LeftParen);
Ast::FunctionParameters params = __parseFunctionParameters(); Ast::FunctionParameters params = __parseFunctionParameters();
FString retTiName = ValueType::Any.name;
Ast::Expression returnType;
if (isThis(TokenType::RightArrow)) // -> if (isThis(TokenType::RightArrow)) // ->
{ {
next(); // skip `->` next(); // skip `->`
expect(TokenType::Identifier); returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
retTiName = currentToken().getValue();
next(); // skip return type
} }
expect(TokenType::LeftBrace); expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement(); Ast::BlockStatement body = __parseBlockStatement();
return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, retTiName, body); return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, returnType, body);
} }
Ast::StructDef Parser::__parseStructDef(bool isPublic) Ast::StructDef Parser::__parseStructDef(bool isPublic)
{ {
@@ -281,13 +283,11 @@ namespace Fig
{ {
throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute"))); throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute")));
} }
FString tiName = ValueType::Any.name; Ast::Expression fieldType = nullptr;
if (isThis(TokenType::Colon)) if (isThis(TokenType::Colon))
{ {
next(); next(); // consume `:`
expect(TokenType::Identifier, u8"type name"); fieldType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
tiName = currentToken().getValue();
next();
} }
Ast::Expression initExpr = nullptr; Ast::Expression initExpr = nullptr;
if (isThis(TokenType::Assign)) if (isThis(TokenType::Assign))
@@ -297,7 +297,7 @@ namespace Fig
initExpr = parseExpression(0); initExpr = parseExpression(0);
} }
expectSemicolon(); expectSemicolon();
return Ast::StructDefField(am, fieldName, tiName, initExpr); return Ast::StructDefField(am, fieldName, fieldType, initExpr);
}; };
std::vector<Ast::Statement> stmts; std::vector<Ast::Statement> stmts;
std::vector<Ast::StructDefField> fields; std::vector<Ast::StructDefField> fields;
@@ -310,10 +310,7 @@ namespace Fig
next(); // consume `}` next(); // consume `}`
break; break;
} }
if (isThis(TokenType::Identifier)) if (isThis(TokenType::Identifier)) { fields.push_back(__parseStructField(false)); }
{
fields.push_back(__parseStructField(false));
}
else if (isThis(TokenType::Public)) else if (isThis(TokenType::Public))
{ {
if (isNext(TokenType::Const)) if (isNext(TokenType::Const))
@@ -353,23 +350,18 @@ namespace Fig
next(); // consume `struct` next(); // consume `struct`
stmts.push_back(__parseStructDef(false)); stmts.push_back(__parseStructDef(false));
} }
else if (isThis(TokenType::Const)) else if (isThis(TokenType::Const)) { fields.push_back(__parseStructField(false)); }
{
fields.push_back(__parseStructField(false));
}
else if (isThis(TokenType::Variable)) else if (isThis(TokenType::Variable))
{ {
throwAddressableError<SyntaxError>(FString("Variables are not allowed to be defined within a structure.")); throwAddressableError<SyntaxError>(
FString("Variables are not allowed to be defined within a structure."));
} }
else else
{ {
throwAddressableError<SyntaxError>(FString("Invalid syntax")); throwAddressableError<SyntaxError>(FString("Invalid syntax"));
} }
} }
if (!braceClosed) if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
{
throwAddressableError<SyntaxError>(FString("braces are not closed"));
}
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts)); return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
} }
@@ -401,32 +393,22 @@ namespace Fig
expect(TokenType::RightArrow); // -> expect(TokenType::RightArrow); // ->
next(); // consume `->` next(); // consume `->`
expect(TokenType::Identifier, u8"return type"); Ast::Expression returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
FString returnType = currentToken().getValue();
next(); // consume return type
if (isThis(TokenType::LeftBrace)) if (isThis(TokenType::LeftBrace))
{ {
Ast::BlockStatement block = __parseBlockStatement(); Ast::BlockStatement block = __parseBlockStatement();
methods.push_back(Ast::InterfaceMethod( methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType, block));
funcName,
paras,
returnType,
block));
continue; continue;
} }
expect(TokenType::Semicolon); expectSemicolon();
next(); // consume `;`
methods.push_back(Ast::InterfaceMethod( methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType));
funcName,
paras,
returnType));
} }
else else
{ {
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column); throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
} }
} }
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic); return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
@@ -447,7 +429,7 @@ namespace Fig
FString structName = currentToken().getValue(); FString structName = currentToken().getValue();
next(); // consume name next(); // consume name
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
next(); // consume `{` next(); // consume `{`
std::vector<Ast::ImplementMethod> methods; std::vector<Ast::ImplementMethod> methods;
@@ -466,14 +448,11 @@ namespace Fig
Ast::FunctionParameters paras = __parseFunctionParameters(); Ast::FunctionParameters paras = __parseFunctionParameters();
expect(TokenType::LeftBrace); expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement(); Ast::BlockStatement body = __parseBlockStatement();
methods.push_back(Ast::ImplementMethod( methods.push_back(Ast::ImplementMethod(funcName, paras, body));
funcName,
paras,
body));
} }
else else
{ {
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column); throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
} }
} }
@@ -494,18 +473,18 @@ namespace Fig
{ {
// entry: current is `try` // entry: current is `try`
next(); // consume `try` next(); // consume `try`
/* /*
try try
{ {
... ...
} }
catch(e: IOError) catch(e: IOError)
{ {
} }
catch(e: TimeOutError) catch(e: TimeOutError)
{ {
} }
*/ */
expect(TokenType::LeftBrace); expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement(); Ast::BlockStatement body = __parseBlockStatement();
@@ -533,15 +512,13 @@ namespace Fig
hasType = true; hasType = true;
} }
expect(TokenType::RightParen); // expect(TokenType::RightParen); //
next(); // consume `)` next(); // consume `)`
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
Ast::BlockStatement catchBody = __parseBlockStatement(); Ast::BlockStatement catchBody = __parseBlockStatement();
if (hasType) if (hasType) { catches.push_back(Ast::Catch(errVarName, errVarType, catchBody)); }
else
{ {
catches.push_back(Ast::Catch(errVarName, errVarType, catchBody));
}
else {
catches.push_back(Ast::Catch(errVarName, catchBody)); catches.push_back(Ast::Catch(errVarName, catchBody));
} }
} }
@@ -549,13 +526,14 @@ namespace Fig
{ {
if (finallyBlock != nullptr) if (finallyBlock != nullptr)
{ {
throw SyntaxError(u8"Duplicate try finally-block", currentAAI.line, currentAAI.column); throwAddressableError<SyntaxError>(
u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
} }
next(); // consume `finally` next(); // consume `finally`
expect(TokenType::LeftBrace); expect(TokenType::LeftBrace);
finallyBlock = __parseBlockStatement(); finallyBlock = __parseBlockStatement();
} }
else else
{ {
break; break;
} }
@@ -563,21 +541,15 @@ namespace Fig
return makeAst<Ast::TrySt>(body, catches, finallyBlock); return makeAst<Ast::TrySt>(body, catches, finallyBlock);
} }
Ast::Statement Parser::__parseStatement() Ast::Statement Parser::__parseStatement(bool allowExp)
{ {
Ast::Statement stmt; Ast::Statement stmt;
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); } if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
else if (isThis(TokenType::Import)) else if (isThis(TokenType::Import)) { stmt = __parseImport(); }
{
stmt = __parseImport();
}
else if (isThis(TokenType::Public)) else if (isThis(TokenType::Public))
{ {
next(); // consume `public` next(); // consume `public`
if (isThis(TokenType::Variable) || isThis(TokenType::Const)) if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(true); }
{
stmt = __parseVarDef(true);
}
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier)) else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
{ {
next(); next();
@@ -585,21 +557,17 @@ namespace Fig
} }
else if (isThis(TokenType::Struct)) else if (isThis(TokenType::Struct))
{ {
next();
stmt = __parseStructDef(true); stmt = __parseStructDef(true);
} }
else if (isThis(TokenType::Interface)) else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
{
stmt = __parseInterfaceDef(true);
}
else else
{ {
throwAddressableError<SyntaxError>(FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`")); throwAddressableError<SyntaxError>(
FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
} }
} }
else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(false); }
{
stmt = __parseVarDef(false);
}
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier)) else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
{ {
next(); next();
@@ -617,57 +585,31 @@ namespace Fig
next(); next();
stmt = __parseInterfaceDef(false); stmt = __parseInterfaceDef(false);
} }
else if (isThis(TokenType::Implement)) else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
{ else if (isThis(TokenType::If)) { stmt = __parseIf(); }
stmt = __parseImplement();
}
else if (isThis(TokenType::If))
{
stmt = __parseIf();
}
else if (isThis(TokenType::Else)) else if (isThis(TokenType::Else))
{ {
throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`")); throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`"));
} }
else if (isThis(TokenType::LeftBrace)) else if (isThis(TokenType::LeftBrace)) { stmt = __parseBlockStatement(); }
{ else if (isThis(TokenType::While)) { stmt = __parseWhile(); }
stmt = __parseBlockStatement(); else if (isThis(TokenType::For)) { stmt = __parseFor(); }
} else if (isThis(TokenType::Return)) { stmt = __parseReturn(); }
else if (isThis(TokenType::While)) else if (isThis(TokenType::Break)) { stmt = __parseBreak(); }
{ else if (isThis(TokenType::Continue)) { stmt = __parseContinue(); }
stmt = __parseWhile(); else if (isThis(TokenType::Throw)) { stmt = __parseThrow(); }
} else if (isThis(TokenType::Try)) { stmt = __parseTry(); }
else if (isThis(TokenType::For)) else if (allowExp)
{
stmt = __parseFor();
}
else if (isThis(TokenType::Return))
{
stmt = __parseReturn();
}
else if (isThis(TokenType::Break))
{
stmt = __parseBreak();
}
else if (isThis(TokenType::Continue))
{
stmt = __parseContinue();
}
else if (isThis(TokenType::Throw))
{
stmt = __parseThrow();
}
else if (isThis(TokenType::Try))
{
stmt = __parseTry();
}
else
{ {
// expression statement // expression statement
Ast::Expression exp = parseExpression(0); Ast::Expression exp = parseExpression(0);
expectSemicolon(); expectSemicolon();
stmt = makeAst<Ast::ExpressionStmtAst>(exp); stmt = makeAst<Ast::ExpressionStmtAst>(exp);
} }
else
{
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
}
return stmt; return stmt;
} }
Ast::BlockStatement Parser::__parseBlockStatement() Ast::BlockStatement Parser::__parseBlockStatement()
@@ -700,7 +642,7 @@ namespace Fig
} }
else else
{ {
condition = parseExpression(0); condition = parseExpression(0, TokenType::LeftBrace);
} }
// parenthesis is not required // parenthesis is not required
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
@@ -723,7 +665,7 @@ namespace Fig
} }
else else
{ {
elifCondition = parseExpression(0); elifCondition = parseExpression(0, TokenType::LeftBrace);
} }
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
Ast::BlockStatement elifBody = __parseBlockStatement(); Ast::BlockStatement elifBody = __parseBlockStatement();
@@ -753,7 +695,7 @@ namespace Fig
} }
else else
{ {
condition = parseExpression(0); condition = parseExpression(0, TokenType::LeftBrace);
} }
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
Ast::BlockStatement body = __parseBlockStatement(); Ast::BlockStatement body = __parseBlockStatement();
@@ -771,12 +713,15 @@ namespace Fig
throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment"); throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment");
} }
if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return) || isThis(TokenType::Break) || isThis(TokenType::Continue)) if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return)
|| isThis(TokenType::Break) || isThis(TokenType::Continue))
{ {
throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment"); throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
} }
return __parseStatement(); Ast::Expression exp = parseExpression(0, TokenType::LeftBrace);
// expectSemicolon(); we dont check the semicolon
return makeAst<Ast::ExpressionStmtAst>(exp);
} }
Ast::For Parser::__parseFor() Ast::For Parser::__parseFor()
{ {
@@ -784,22 +729,20 @@ namespace Fig
// TODO: support enumeration // TODO: support enumeration
next(); // consume `for` next(); // consume `for`
bool paren = isThis(TokenType::LeftParen); bool paren = isThis(TokenType::LeftParen);
if (paren) if (paren) next(); // consume `(`
next(); // consume `(`
// support 3-part for loop // support 3-part for loop
// for init; condition; increment {} // for init; condition; increment {}
Ast::Statement initStmt = __parseStatement(); // auto check `` Ast::Statement initStmt = __parseStatement(false); // auto check ``
Ast::Expression condition = parseExpression(0); Ast::Expression condition = parseExpression(0);
expectSemicolon(); // auto consume `;` expectSemicolon(); // auto consume `;`
Ast::Statement incrementStmt = nullptr; Ast::Statement incrementStmt = nullptr;
if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment? if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment?
{ {
auto guard = disableSemicolon(); // auto guard = disableSemicolon();
incrementStmt = __parseIncrementStatement(); incrementStmt = __parseIncrementStatement();
} // after parse increment, semicolon check state restored } // after parse increment, semicolon check state restored
if (paren) if (paren) expectConsume(TokenType::RightParen); // consume `)` if has `(`
expectConsume(TokenType::RightParen); // consume `)` if has `(`
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}` Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}`
return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body); return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body);
@@ -906,7 +849,7 @@ namespace Fig
return makeAst<Ast::MapExprAst>(val); return makeAst<Ast::MapExprAst>(val);
} }
Ast::InitExpr Parser::__parseInitExpr(FString structName) Ast::InitExpr Parser::__parseInitExpr(Ast::Expression structe)
{ {
// entry: current is `{` // entry: current is `{`
next(); // consume `{` next(); // consume `{`
@@ -917,16 +860,13 @@ namespace Fig
.2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered .2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered
.3 Person {name, age, sex}; .3 Person {name, age, sex};
*/ */
uint8_t mode; // 0=undetermined, 1=positional, 2=named, 3=shorthand uint8_t mode = 0; // 0=undetermined, 1=positional, 2=named, 3=shorthand
while (!isThis(TokenType::RightBrace)) while (!isThis(TokenType::RightBrace))
{ {
if (mode == 0) if (mode == 0)
{ {
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon)) if (isThis(TokenType::Identifier) && isNext(TokenType::Colon)) { mode = 2; }
{
mode = 2;
}
else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace))) else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace)))
{ {
mode = 3; mode = 3;
@@ -970,17 +910,19 @@ namespace Fig
} }
else if (!isThis(TokenType::RightBrace)) else if (!isThis(TokenType::RightBrace))
{ {
throwAddressableError<SyntaxError>(FString( throwAddressableError<SyntaxError>(
std::format("Expect `,` or `}}` in struct initialization expression, got {}", FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
currentToken().toString().toBasicString()))); currentToken().toString().toBasicString())));
} }
} }
expect(TokenType::RightBrace); expect(TokenType::RightBrace);
next(); // consume `}` next(); // consume `}`
return makeAst<Ast::InitExprAst>(structName, args, return makeAst<Ast::InitExprAst>(
(mode == 1 ? Ast::InitExprAst::InitMode::Positional : structe,
(mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand))); args,
static_cast<Ast::InitExprAst::InitMode>(mode));
} }
Ast::Expression Parser::__parseTupleOrParenExpr() Ast::Expression Parser::__parseTupleOrParenExpr()
{ {
next(); next();
@@ -1002,8 +944,7 @@ namespace Fig
{ {
next(); // consume ',' next(); // consume ','
if (currentToken().getType() == TokenType::RightParen) if (currentToken().getType() == TokenType::RightParen) break;
break;
elements.push_back(parseExpression(0)); elements.push_back(parseExpression(0));
} }
@@ -1054,10 +995,7 @@ namespace Fig
expect(TokenType::Identifier, u8"package name"); expect(TokenType::Identifier, u8"package name");
path.push_back(currentToken().getValue()); path.push_back(currentToken().getValue());
next(); // consume package name next(); // consume package name
if (isThis(TokenType::Semicolon)) if (isThis(TokenType::Semicolon)) { break; }
{
break;
}
else if (isThis(TokenType::Dot)) else if (isThis(TokenType::Dot))
{ {
next(); // consume `.` next(); // consume `.`
@@ -1067,8 +1005,7 @@ namespace Fig
throw SyntaxError(); throw SyntaxError();
} }
} }
expect(TokenType::Semicolon); expectSemicolon();
next(); // consume `;`
return makeAst<Ast::ImportSt>(path); return makeAst<Ast::ImportSt>(path);
} }
@@ -1078,8 +1015,7 @@ namespace Fig
Ast::Operator op; Ast::Operator op;
Token tok = currentToken(); Token tok = currentToken();
if (tok == EOFTok) if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
if (tok.getType() == stop || tok.getType() == stop2) if (tok.getType() == stop || tok.getType() == stop2)
{ {
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression")); if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
@@ -1117,39 +1053,56 @@ namespace Fig
{ {
FString id = tok.getValue(); FString id = tok.getValue();
next(); next();
if (currentToken().getType() == TokenType::LeftBrace) lhs = __parseVarExpr(id);
{
lhs = __parseInitExpr(id); // a_struct{init...}
}
else
{
lhs = __parseVarExpr(id);
}
} }
else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType())))) else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType()))))
{ {
// prefix // prefix
next(); next();
lhs = __parsePrefix(op, getRightBindingPower(op)); lhs = makeAst<Ast::UnaryExprAst>(op, parseExpression(bp, stop, stop2));
}
else if (tok.getType() == TokenType::New)
{
// `new` now is an independent syntax
next();
Ast::Expression operand = parseExpression(bp, TokenType::LeftBrace);
expect(TokenType::LeftBrace);
lhs = __parseInitExpr(operand);
} }
else else
{ {
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression")); throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
} }
// infix / (postfix) ? // infix / (postfix) ?
while (true) while (true)
{ {
tok = currentToken(); tok = currentToken();
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break; if (tok.getType() == stop || tok.getType() == stop2 || tok == EOFTok) break;
/* Postfix */ /* Postfix */
if (tok.getType() == TokenType::LeftBrace)
{
throwAddressableError<SyntaxError>(
FString(u8"Since Fig v0.4.2, please use new struct{} to avoid syntax ambiguity"));
}
if (tok.getType() == TokenType::LeftParen) if (tok.getType() == TokenType::LeftParen)
{ {
lhs = __parseCall(lhs); lhs = __parseCall(lhs);
continue; continue;
} }
// else if (tok.getType() == TokenType::LeftBrace) { lhs = __parseInitExpr(lhs); }
/*
since Fig v0.4.2, use new struct{};
if a == A{}
is A{} struct init?
or A a variable, {} is the body?
fuck.
*/
// member access: a.b // member access: a.b
if (tok.getType() == TokenType::Dot) if (tok.getType() == TokenType::Dot)
@@ -1169,22 +1122,24 @@ namespace Fig
if (tok.getType() == TokenType::LeftBracket) if (tok.getType() == TokenType::LeftBracket)
{ {
next(); // consume '[' next(); // consume '['
auto indexExpr = parseExpression(0, TokenType::RightBracket); auto indexExpr = parseExpression(0, TokenType::RightBracket, stop2);
expect(TokenType::RightBracket); expect(TokenType::RightBracket);
next(); // consume ']' next(); // consume ']'
lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr); lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
continue; continue;
} }
// ternary // ternary
if (tok.getType() == TokenType::Question) if (tok.getType() == TokenType::Question)
{ {
auto [lbp, rbp] = getBindingPower(Ast::Operator::TernaryCond);
if (bp >= lbp) break;
next(); // consume ? next(); // consume ?
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon); Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
expect(TokenType::Colon); expectConsume(TokenType::Colon);
next(); // consume :
Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2); Ast::Expression falseExpr = parseExpression(0);
lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr); lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
continue; continue;
} }
@@ -1192,11 +1147,11 @@ namespace Fig
if (!isTokenOp(tok)) break; if (!isTokenOp(tok)) break;
op = Ast::TokenToOp.at(tok.getType()); op = Ast::TokenToOp.at(tok.getType());
Precedence lbp = getLeftBindingPower(op); auto [lbp, rbp] = getBindingPower(op);
if (bp >= lbp) break; if (bp >= lbp) break;
next(); // consume op next(); // consume op
lhs = __parseInfix(lhs, op, getRightBindingPower(op)); lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(rbp, stop, stop2));
} }
return lhs; return lhs;
@@ -1206,20 +1161,15 @@ namespace Fig
{ {
output.clear(); output.clear();
Token tok = currentToken(); Token tok = currentToken();
if (tok == EOFTok) if (tok == EOFTok) { return output; }
{
return output;
}
while (!isEOF()) while (!isEOF())
{ {
auto stmt = __parseStatement(); auto stmt = __parseStatement();
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt) if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
{ {
throw SyntaxError( throwAddressableError<SyntaxError>(
u8"Package must be at the beginning of the file", u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
currentAAI.line,
currentAAI.column);
} }
pushNode(stmt); pushNode(stmt);
} }

View File

@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <Ast/astBase.hpp>
#include <Ast/ast.hpp> #include <Ast/ast.hpp>
#include <Lexer/lexer.hpp> #include <Lexer/lexer.hpp>
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Error/error.hpp> #include <Error/error.hpp>
#include <print> #include <memory>
#include <source_location> #include <source_location>
#include <unordered_map> #include <unordered_map>
@@ -21,6 +22,9 @@ namespace Fig
std::vector<Ast::AstBase> output; std::vector<Ast::AstBase> output;
std::vector<Token> previousTokens; std::vector<Token> previousTokens;
std::shared_ptr<FString> sourcePathPtr;
std::shared_ptr<std::vector<FString>> sourceLinesPtr;
size_t tokenPruduced = 0; size_t tokenPruduced = 0;
size_t currentTokenIndex = 0; size_t currentTokenIndex = 0;
@@ -38,15 +42,8 @@ namespace Fig
bool original; bool original;
public: public:
SemicolonDisabler(Parser *parser) : SemicolonDisabler(Parser *parser) : p(parser), original(p->needSemicolon) { p->needSemicolon = false; }
p(parser), original(p->needSemicolon) ~SemicolonDisabler() { p->needSemicolon = original; }
{
p->needSemicolon = false;
}
~SemicolonDisabler()
{
p->needSemicolon = original;
}
// disable copy and assign // disable copy and assign
SemicolonDisabler(const SemicolonDisabler &) = delete; SemicolonDisabler(const SemicolonDisabler &) = delete;
SemicolonDisabler &operator=(const SemicolonDisabler &) = delete; SemicolonDisabler &operator=(const SemicolonDisabler &) = delete;
@@ -65,14 +62,8 @@ namespace Fig
output.push_back(node); output.push_back(node);
} }
bool isTokenSymbol(Token tok) bool isTokenSymbol(Token tok) { return Lexer::symbol_map.contains(tok.getValue()); }
{ bool isTokenOp(Token tok) { return Ast::TokenToOp.contains(tok.getType()); }
return Lexer::symbol_map.contains(tok.getValue());
}
bool isTokenOp(Token tok)
{
return Ast::TokenToOp.contains(tok.getType());
}
bool isEOF() bool isEOF()
{ {
if (tokenPruduced == 0) return false; if (tokenPruduced == 0) return false;
@@ -82,32 +73,33 @@ namespace Fig
public: public:
using Precedence = uint32_t; using Precedence = uint32_t;
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence; static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
Parser(const Lexer &_lexer) : static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
lexer(_lexer)
Parser(const Lexer &_lexer, FString _sourcePath, std::vector<FString> _sourceLines) : lexer(_lexer)
{ {
sourcePathPtr = std::make_shared<FString>(_sourcePath);
sourceLinesPtr = std::make_shared<std::vector<FString>>(_sourceLines);
} }
AddressableError* getError() const AddressableError *getError() const { return error.get(); }
{
return error.get();
}
template <class _ErrT, typename = AddressableError> template <class _ErrT, typename = AddressableError>
void throwAddressableError(FString msg, size_t line, size_t column, std::source_location loc = std::source_location::current()) void throwAddressableError(FString msg,
size_t line,
size_t column,
std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError"); _ErrT spError(msg, line, column, *sourcePathPtr, *sourceLinesPtr, loc);
_ErrT spError(msg, line, column, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
throw spError; throw spError;
} }
template <class _ErrT, typename = AddressableError> template <class _ErrT, typename = AddressableError>
void throwAddressableError(FString msg, std::source_location loc = std::source_location::current()) void throwAddressableError(FString msg, std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError");
// line, column provide by `currentAAI` // line, column provide by `currentAAI`
_ErrT spError(msg, currentAAI.line, currentAAI.column, loc); _ErrT spError(msg, currentAAI.line, currentAAI.column, *sourcePathPtr, *sourceLinesPtr, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
throw spError; throw spError;
} }
@@ -115,22 +107,15 @@ namespace Fig
template <class _ErrT, typename = UnaddressableError> template <class _ErrT, typename = UnaddressableError>
void throwUnaddressableError(FString msg, std::source_location loc = std::source_location::current()) void throwUnaddressableError(FString msg, std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError");
_ErrT spError(msg, loc); _ErrT spError(msg, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
throw spError; throw spError;
} }
void setCurrentAAI(Ast::AstAddressInfo _aai) void setCurrentAAI(Ast::AstAddressInfo _aai) { currentAAI = std::move(_aai); }
{
currentAAI = std::move(_aai);
}
Ast::AstAddressInfo getCurrentAAI() const Ast::AstAddressInfo getCurrentAAI() const { return currentAAI; }
{
return currentAAI;
}
inline const Token &nextToken() inline const Token &nextToken()
{ {
@@ -143,7 +128,8 @@ namespace Fig
if (int64_t(currentTokenIndex - 1) < int64_t(0)) if (int64_t(currentTokenIndex - 1) < int64_t(0))
// 同下 next注释 // 同下 next注释
{ {
throw std::runtime_error("Internal Error in Parser::rollbackToken, trying to rollback but it's already on the begin"); throw std::runtime_error(
"Internal Error in Parser::rollbackToken, trying to rollback but it's already on the begin");
} }
currentTokenIndex--; currentTokenIndex--;
} }
@@ -152,10 +138,14 @@ namespace Fig
if (int64_t(currentTokenIndex) < (int64_t(tokenPruduced) - 1)) if (int64_t(currentTokenIndex) < (int64_t(tokenPruduced) - 1))
{ {
/* /*
必须两个都显示转换为int64_t.否则负数时会超出范围变成int64_t max, 并且 CTI也需要显示转换否则转换完的pruduced又会被转回去变为 int64_t max 必须两个都显示转换为int64_t.否则负数时会超出范围变成int64_t max, 并且
CTI也需要显示转换否则转换完的pruduced又会被转回去变为 int64_t max
*/ */
currentTokenIndex++; currentTokenIndex++;
setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line, .column = currentToken().column}); setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line,
.column = currentToken().column,
.sourcePath = sourcePathPtr,
.sourceLines = sourceLinesPtr});
return; return;
} }
if (isEOF()) return; if (isEOF()) return;
@@ -163,7 +153,11 @@ namespace Fig
tokenPruduced++; tokenPruduced++;
if (tok == IllegalTok) throw lexer.getError(); if (tok == IllegalTok) throw lexer.getError();
currentTokenIndex = tokenPruduced - 1; currentTokenIndex = tokenPruduced - 1;
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line, .column = tok.column}); setCurrentAAI(Ast::AstAddressInfo{.line = tok.line,
.column = tok.column,
.sourcePath = sourcePathPtr,
.sourceLines = sourceLinesPtr});
previousTokens.push_back(tok); previousTokens.push_back(tok);
} }
inline const Token &currentToken() inline const Token &currentToken()
@@ -184,18 +178,11 @@ namespace Fig
return tok; return tok;
} }
std::pair<Precedence, Precedence> getBindingPower(Ast::Operator op) const std::pair<Precedence, Precedence> &getBindingPower(Ast::Operator op) const { return opPrecedence.at(op); }
{ Precedence getLeftBindingPower(Ast::Operator op) const { return getBindingPower(op).first; }
return opPrecedence.at(op); Precedence getRightBindingPower(Ast::Operator op) const { return getBindingPower(op).second; }
}
Precedence getLeftBindingPower(Ast::Operator op) const Precedence &getUnaryBp(Ast::Operator op) const { return unaryOpPrecedence.at(op); }
{
return getBindingPower(op).first;
}
Precedence getRightBindingPower(Ast::Operator op)
{
return getBindingPower(op).second;
}
// template <class _Tp, class... Args> // template <class _Tp, class... Args>
// std::shared_ptr<_Tp> makeAst(Args &&...args) // std::shared_ptr<_Tp> makeAst(Args &&...args)
@@ -217,8 +204,9 @@ namespace Fig
if (peekToken().getType() != type) if (peekToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
magic_enum::enum_name(type), magic_enum::enum_name(type),
magic_enum::enum_name(peekToken().getType()))), loc); magic_enum::enum_name(peekToken().getType()))),
loc);
} }
} }
@@ -226,9 +214,11 @@ namespace Fig
{ {
if (currentToken().getType() != type) if (currentToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(
magic_enum::enum_name(type), FString(std::format("Expected `{}`, but got `{}`",
magic_enum::enum_name(currentToken().getType()))), loc); magic_enum::enum_name(type),
magic_enum::enum_name(currentToken().getType()))),
loc);
} }
} }
@@ -237,8 +227,9 @@ namespace Fig
if (peekToken().getType() != type) if (peekToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
expected.toBasicString(), expected.toBasicString(),
magic_enum::enum_name(peekToken().getType()))), loc); magic_enum::enum_name(peekToken().getType()))),
loc);
} }
} }
@@ -246,18 +237,17 @@ namespace Fig
{ {
if (currentToken().getType() != type) if (currentToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(
expected.toBasicString(), FString(std::format("Expected `{}`, but got `{}`",
magic_enum::enum_name(currentToken().getType()))), loc); expected.toBasicString(),
magic_enum::enum_name(currentToken().getType()))),
loc);
} }
} }
[[nodiscard]] SemicolonDisabler disableSemicolon() [[nodiscard]] SemicolonDisabler disableSemicolon() { return SemicolonDisabler(this); }
{
return SemicolonDisabler(this);
}
void expectSemicolon() void expectSemicolon(std::source_location loc = std::source_location::current())
{ {
// if need semicolon and stream has `;`, consume it. if not need semicolon, do nothing // if need semicolon and stream has `;`, consume it. if not need semicolon, do nothing
@@ -272,29 +262,23 @@ namespace Fig
} }
// normal semicolon check // normal semicolon check
expectConsume(TokenType::Semicolon); expectConsume(TokenType::Semicolon, loc);
} }
void expectConsume(TokenType type, FString expected) void expectConsume(TokenType type, FString expected, std::source_location loc = std::source_location::current())
{ {
expect(type, expected); expect(type, expected, loc);
next(); next();
} }
void expectConsume(TokenType type) void expectConsume(TokenType type, std::source_location loc = std::source_location::current())
{ {
expect(type); expect(type, loc);
next(); next();
} }
bool isNext(TokenType type) bool isNext(TokenType type) { return peekToken().getType() == type; }
{ bool isThis(TokenType type) { return currentToken().getType() == type; }
return peekToken().getType() == type;
}
bool isThis(TokenType type)
{
return currentToken().getType() == type;
}
static constexpr FString varDefTypeFollowed = u8"(Followed)"; static constexpr FString varDefTypeFollowed = u8"(Followed)";
@@ -313,28 +297,31 @@ namespace Fig
Ast::VarExpr __parseVarExpr(FString); Ast::VarExpr __parseVarExpr(FString);
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::InterfaceDef __parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool) Ast::InterfaceDef
Ast::Implement __parseImplement(); // entry: current is `impl` __parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool)
Ast::Implement __parseImplement(); // entry: current is `impl`
Ast::Throw __parseThrow(); // entry: current is `throw` Ast::Throw __parseThrow(); // entry: current is `throw`
Ast::Try __parseTry(); // entry: current is `try` Ast::Try __parseTry(); // entry: current is `try`
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::Expression __parseCall(Ast::Expression);
Ast::ListExpr __parseListExpr(); // 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::ListExpr __parseListExpr(); // entry: current is `[`
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(` Ast::MapExpr __parseMapExpr(); // entry: current is `{`
Ast::InitExpr __parseInitExpr(Ast::Expression); // entry: current is `{`, ahead is struct type exp.
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
Ast::Import __parseImport(); // entry: current is Token::Import Ast::Import __parseImport(); // entry: current is Token::Import
Ast::Statement __parseStatement(); // entry: (idk) Ast::Statement __parseStatement(bool = true); // entry: (idk)
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();
}; };

View File

@@ -31,6 +31,7 @@ namespace Fig
For, // for For, // for
If, // if If, // if
Else, // else Else, // else
New, // new
Struct, // struct Struct, // struct
Interface, // interface Interface, // interface
Implement, // impl Implement, // impl

View File

@@ -111,7 +111,7 @@ private:
printFString(node->name, 0); printFString(node->name, 0);
printIndent(indent + 2); printIndent(indent + 2);
std::cout << "Type: "; std::cout << "Type: ";
printFString(node->typeName, 0); printFString(node->declaredType->toString(), 0);
if (node->expr) if (node->expr)
{ {
printIndent(indent + 2); printIndent(indent + 2);

29
src/VMValue/VMValue.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include <VMValue/VMValue.hpp>
#include <cassert>
#include <string>
namespace Fig
{
FString Value::toString() const
{
if (static_cast<int>(type) > static_cast<int>(Double))
{
return heap->toString();
}
switch (type)
{
case Null:
return u8"null";
case Bool:
return (b ? u8"true" : u8"false");
case Int:
return FString(std::to_string(i));
case Double:
return FString(std::to_string(d));
default:
assert(false);
}
}
};

91
src/VMValue/VMValue.hpp Normal file
View File

@@ -0,0 +1,91 @@
#pragma once
/*
value system for virtual machine
not Evaluator value
*/
#include <Core/fig_string.hpp>
#include <cstdint>
namespace Fig
{
struct HeapObject;
struct Value
{
struct NullObject {};
enum _Type : uint8_t
{
Null = 0,
Bool,
Int,
Double,
/* Complex types, alloc in heap*/
String,
// Function,
// StructType,
// StructInstance,
// List,
// Map,
// Module,
// InterfaceType
} type;
union
{
NullObject n;
bool b;
int64_t i;
double d;
HeapObject *heap;
};
Value()
{
type = Null;
n = NullObject();
}
Value(bool _b)
{
type = Bool;
b = _b;
}
Value(int64_t _i)
{
type = Int;
i = _i;
}
Value(double _d)
{
type = Double;
d = _d;
}
FString toString() const;
};
struct HeapObject
{
Value::_Type type; // > 3
virtual FString toString() const = 0;
};
struct String : HeapObject
{
FString value;
virtual FString toString() const override
{
return value;
}
};
};

View File

@@ -0,0 +1,43 @@
/*
███████████ █████ █████ ██████████ ███████████ █████ █████████ █████ █████████ ██████ █████ █████████ █████ █████ █████████ █████████ ██████████
░█░░░███░░░█░░███ ░░███ ░░███░░░░░█ ░░███░░░░░░█░░███ ███░░░░░███ ░░███ ███░░░░░███ ░░██████ ░░███ ███░░░░░███░░███ ░░███ ███░░░░░███ ███░░░░░███░░███░░░░░█
░ ░███ ░ ░███ ░███ ░███ █ ░ ░███ █ ░ ░███ ███ ░░░ ░███ ░███ ░███ ░███░███ ░███ ███ ░░░ ░███ ░███ ░███ ░███ ███ ░░░ ░███ █ ░
░███ ░███████████ ░██████ ░███████ ░███ ░███ ░███ ░███████████ ░███░░███░███ ░███ ░███ ░███ ░███████████ ░███ ░██████
░███ ░███░░░░░███ ░███░░█ ░███░░░█ ░███ ░███ █████ ░███ ░███░░░░░███ ░███ ░░██████ ░███ █████ ░███ ░███ ░███░░░░░███ ░███ █████ ░███░░█
░███ ░███ ░███ ░███ ░ █ ░███ ░ ░███ ░░███ ░░███ ░███ █ ░███ ░███ ░███ ░░█████ ░░███ ░░███ ░███ ░███ ░███ ░███ ░░███ ░░███ ░███ ░ █
█████ █████ █████ ██████████ █████ █████ ░░█████████ ███████████ █████ █████ █████ ░░█████ ░░█████████ ░░████████ █████ █████ ░░█████████ ██████████
░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
Copyright (C) 2020-2026 PuqiAR
This software is licensed under the MIT License. See LICENSE for details.
*/
// DO NOT USE CLANG-FORMAT FOR THIS FILE
#include <Bytecode/Bytecode.hpp>
#include <iostream>
int main()
{
using namespace Fig;
std::vector<OpCodeType> src;
{
using enum Bytecode;
src = {
0x21, // LOAD_TRUE
0x23, 0x7f, // LOAD_CON8 0x7f
0x24, 0x12, 0x34, // LOAD_CON16 0x1234
0x25, 0x12, 0x34, 0x56, 0x78, // LOAD_CON32 0x12345678
0x63, 0x12, 0x34, 0x56, 0x78 // JUMP32_IF_TRUE
};
FString r = reverseCompile(src);
std::cout << r.toBasicString() << std::endl;
}
}

View File

@@ -7,7 +7,6 @@ target("Fig")
set_kind("binary") set_kind("binary")
set_languages("c++23") set_languages("c++23")
add_ldflags("-static", {force = true}) add_ldflags("-static", {force = true})
if is_plat("linux") then if is_plat("linux") then
-- Linux: clang + libc++ -- Linux: clang + libc++
@@ -27,15 +26,52 @@ target("Fig")
end end
add_files("src/main.cpp") add_files("src/Evaluator/main.cpp")
add_files("src/Core/warning.cpp") add_files("src/Core/warning.cpp")
add_files("src/Core/runtimeTime.cpp")
add_files("src/Evaluator/evaluator.cpp") add_files("src/Evaluator/evaluator.cpp")
add_files("src/Evaluator/Value/value.cpp")
add_files("src/Lexer/lexer.cpp") add_files("src/Lexer/lexer.cpp")
add_files("src/Parser/parser.cpp") add_files("src/Parser/parser.cpp")
add_files("src/Value/value.cpp")
add_includedirs("src") add_includedirs("src")
add_includedirs("src/Evaluator")
set_warnings("all") set_warnings("all")
add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"") add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"")
-- -- Bytecode VM target
-- target("Figc")
-- set_kind("binary")
-- set_languages("c++23")
-- add_ldflags("-static", {force = true})
-- if is_plat("linux") then
-- -- Linux: clang + libc++
-- set_toolchains("clang")
-- add_cxxflags("-stdlib=libc++")
-- add_ldflags("-stdlib=libc++")
-- elseif is_plat("windows") then
-- -- 1. CI cross (Linux -> Windows)
-- -- 2. local dev (Windows + llvm-mingw)
-- set_toolchains("mingw") -- llvm-mingw
-- add_ldflags("-Wl,--stack,268435456")
-- -- set_toolchains("clang")
-- -- static lib
-- -- add_ldflags("-target x86_64-w64-mingw32", "-static")
-- -- add_cxxflags("-stdlib=libc++")
-- -- add_ldflags("-stdlib=libc++")
-- end
-- add_includedirs("src/Evaluator")
-- add_files("src/Evaluator/Value/value.cpp")
-- add_files("src/VirtualMachine/main.cpp")
-- add_files("src/Core/warning.cpp")
-- add_files("src/Lexer/lexer.cpp")
-- add_files("src/Parser/parser.cpp")
-- add_includedirs("src")
-- set_warnings("all")
-- add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"")