forked from PuqiAR/Fig-TreeWalker
Compare commits
13 Commits
v0.3.7-alp
...
v0.4.2-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| ca4ae143b4 | |||
| 21641f888e | |||
| def69e031f | |||
| 009a70fc64 | |||
| e01b4e9849 | |||
| da262a4cf1 | |||
| f76e28ee8d | |||
| a324cf17f6 | |||
| caf058dd55 | |||
| 9e3f17711f | |||
| d398d457b5 | |||
| ccf80536b3 | |||
| 13fdbec0c4 |
@@ -11,3 +11,69 @@ invalid!
|
||||
|
||||
const Pi := 3.14; // recommended, auto detect type
|
||||
// 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
|
||||
*/
|
||||
65
ExampleCodes/SpeedTest/fibBenchmark.fig
Normal file
65
ExampleCodes/SpeedTest/fibBenchmark.fig
Normal 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);
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "fig-vscode",
|
||||
"displayName": "Fig Language",
|
||||
"description": "VSCode extension for Fig language with syntax highlighting",
|
||||
"version": "0.0.2",
|
||||
"version": "0.4.2",
|
||||
"publisher": "PuqiAR",
|
||||
"engines": {
|
||||
"vscode": "^1.90.0"
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"patterns": [
|
||||
{
|
||||
"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" }
|
||||
]
|
||||
|
||||
@@ -23,14 +23,14 @@ namespace Fig::Ast
|
||||
FString name;
|
||||
FunctionParameters paras;
|
||||
bool isPublic;
|
||||
FString retType;
|
||||
Expression retType;
|
||||
BlockStatement body;
|
||||
FunctionDefSt() :
|
||||
retType(ValueType::Null.name)
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Fig::Ast
|
||||
{
|
||||
FString name;
|
||||
FunctionParameters paras;
|
||||
FString returnType;
|
||||
Expression returnType;
|
||||
|
||||
BlockStatement defaultBody = nullptr; // nullptr is non-default func
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ namespace Fig::Ast
|
||||
{
|
||||
AccessModifier am;
|
||||
FString fieldName;
|
||||
FString tiName;
|
||||
Expression declaredType;
|
||||
Expression defaultValueExpr;
|
||||
|
||||
StructDefField() {}
|
||||
StructDefField(AccessModifier _am, FString _fieldName, FString _tiName, Expression _defaultValueExpr) :
|
||||
am(std::move(_am)), fieldName(std::move(_fieldName)), tiName(std::move(_tiName)), defaultValueExpr(std::move(_defaultValueExpr))
|
||||
StructDefField(AccessModifier _am, FString _fieldName, Expression _declaredType, Expression _defaultValueExpr) :
|
||||
am(std::move(_am)), fieldName(std::move(_fieldName)), declaredType(std::move(_declaredType)), defaultValueExpr(std::move(_defaultValueExpr))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,22 +11,28 @@ namespace Fig::Ast
|
||||
bool isPublic;
|
||||
bool isConst;
|
||||
FString name;
|
||||
FString typeName;
|
||||
// FString typeName;
|
||||
Expression declaredType;
|
||||
Expression expr;
|
||||
|
||||
VarDefAst() :
|
||||
typeName(ValueType::Any.name)
|
||||
bool followupType;
|
||||
|
||||
VarDefAst()
|
||||
{
|
||||
type = AstType::VarDefSt;
|
||||
declaredType = nullptr;
|
||||
expr = nullptr;
|
||||
followupType = false;
|
||||
}
|
||||
VarDefAst(bool _isPublic, bool _isConst, FString _name, FString _info, Expression _expr) :
|
||||
typeName(std::move(_info))
|
||||
VarDefAst(bool _isPublic, bool _isConst, FString _name, Expression _declaredType, Expression _expr, bool _followupType)
|
||||
{
|
||||
type = AstType::VarDefSt;
|
||||
isPublic = _isPublic;
|
||||
isConst = _isConst;
|
||||
name = std::move(_name);
|
||||
declaredType = std::move(_declaredType);
|
||||
expr = std::move(_expr);
|
||||
followupType = _followupType;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,14 +26,15 @@ namespace Fig::Ast
|
||||
TernaryExpr,
|
||||
|
||||
/* Postfix */
|
||||
MemberExpr, // a.b
|
||||
IndexExpr, // a[b]
|
||||
MemberExpr, // a.b
|
||||
IndexExpr, // a[b]
|
||||
FunctionCall, // a()
|
||||
|
||||
/* Literals */
|
||||
ListExpr, // [1, "2", 3
|
||||
TupleExpr, // (1, 2, 3)
|
||||
MapExpr, // {a: 1}
|
||||
|
||||
InitExpr, // struct{"123", 456}
|
||||
FunctionLiteralExpr,
|
||||
|
||||
@@ -100,6 +101,8 @@ namespace Fig::Ast
|
||||
struct AstAddressInfo
|
||||
{
|
||||
size_t line, column;
|
||||
std::shared_ptr<FString> sourcePath;
|
||||
std::shared_ptr<std::vector<FString>> sourceLines;
|
||||
};
|
||||
|
||||
class _AstBase
|
||||
@@ -117,30 +120,20 @@ namespace Fig::Ast
|
||||
|
||||
_AstBase() {}
|
||||
|
||||
void setAAI(AstAddressInfo _aai)
|
||||
{
|
||||
aai = std::move(_aai);
|
||||
}
|
||||
void setAAI(AstAddressInfo _aai) { aai = std::move(_aai); }
|
||||
|
||||
virtual FString typeName()
|
||||
{
|
||||
return FString::fromStringView(
|
||||
FStringView::fromBasicStringView(magic_enum::enum_name(type)));
|
||||
return FString::fromStringView(FStringView::fromBasicStringView(magic_enum::enum_name(type)));
|
||||
}
|
||||
virtual FString toString()
|
||||
{
|
||||
return FString(std::format("<Base Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
}
|
||||
|
||||
AstAddressInfo getAAI()
|
||||
{
|
||||
return aai;
|
||||
}
|
||||
AstAddressInfo getAAI() { return aai; }
|
||||
|
||||
AstType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
AstType getType() { return type; }
|
||||
};
|
||||
|
||||
class StatementAst : public _AstBase
|
||||
@@ -148,10 +141,7 @@ namespace Fig::Ast
|
||||
public:
|
||||
using _AstBase::_AstBase;
|
||||
using _AstBase::operator=;
|
||||
StatementAst()
|
||||
{
|
||||
type = AstType::StatementBase;
|
||||
}
|
||||
StatementAst() { type = AstType::StatementBase; }
|
||||
|
||||
virtual FString toString() override
|
||||
{
|
||||
@@ -162,10 +152,7 @@ namespace Fig::Ast
|
||||
class EofStmt final : public StatementAst
|
||||
{
|
||||
public:
|
||||
EofStmt()
|
||||
{
|
||||
type = AstType::StatementBase;
|
||||
}
|
||||
EofStmt() { type = AstType::StatementBase; }
|
||||
|
||||
virtual FString toString() override
|
||||
{
|
||||
@@ -178,10 +165,7 @@ namespace Fig::Ast
|
||||
public:
|
||||
using _AstBase::_AstBase;
|
||||
using _AstBase::operator=;
|
||||
ExpressionAst()
|
||||
{
|
||||
type = AstType::ExpressionBase;
|
||||
}
|
||||
ExpressionAst() { type = AstType::ExpressionBase; }
|
||||
|
||||
virtual FString toString() override
|
||||
{
|
||||
@@ -240,41 +224,22 @@ namespace Fig::Ast
|
||||
static const std::unordered_set<Operator> unaryOps{
|
||||
Operator::Not, // !
|
||||
Operator::Subtract, // -
|
||||
Operator::BitNot, // ~
|
||||
Operator::BitNot, // ~
|
||||
|
||||
Operator::BitAnd, // reference operator &
|
||||
};
|
||||
static const std::unordered_set<Operator> binaryOps{
|
||||
Operator::Add,
|
||||
Operator::Subtract,
|
||||
Operator::Multiply,
|
||||
Operator::Divide,
|
||||
Operator::Modulo,
|
||||
Operator::Power,
|
||||
Operator::And,
|
||||
Operator::Or,
|
||||
Operator::Add, Operator::Subtract, Operator::Multiply, Operator::Divide,
|
||||
Operator::Modulo, Operator::Power, Operator::And, Operator::Or,
|
||||
|
||||
Operator::Equal,
|
||||
Operator::NotEqual,
|
||||
Operator::Less,
|
||||
Operator::LessEqual,
|
||||
Operator::Greater,
|
||||
Operator::GreaterEqual,
|
||||
Operator::Is,
|
||||
Operator::Equal, Operator::NotEqual, Operator::Less, Operator::LessEqual,
|
||||
Operator::Greater, Operator::GreaterEqual, Operator::Is,
|
||||
|
||||
Operator::BitAnd,
|
||||
Operator::BitOr,
|
||||
Operator::BitXor,
|
||||
Operator::BitNot,
|
||||
Operator::ShiftLeft,
|
||||
Operator::ShiftRight,
|
||||
Operator::BitAnd, Operator::BitOr, Operator::BitXor, Operator::BitNot,
|
||||
Operator::ShiftLeft, Operator::ShiftRight,
|
||||
|
||||
Operator::Assign,
|
||||
Operator::PlusAssign,
|
||||
Operator::MinusAssign,
|
||||
Operator::AsteriskAssign,
|
||||
Operator::SlashAssign,
|
||||
Operator::CaretAssign
|
||||
Operator::Assign, Operator::PlusAssign, Operator::MinusAssign, Operator::AsteriskAssign,
|
||||
Operator::SlashAssign, Operator::CaretAssign
|
||||
|
||||
// Operator::Walrus,
|
||||
// Operator::Dot
|
||||
@@ -350,19 +315,9 @@ namespace Fig::Ast
|
||||
{
|
||||
public:
|
||||
std::vector<Statement> stmts;
|
||||
BlockStatementAst()
|
||||
{
|
||||
type = AstType::BlockStatement;
|
||||
}
|
||||
BlockStatementAst(std::vector<Statement> _stmts) :
|
||||
stmts(std::move(_stmts))
|
||||
{
|
||||
type = AstType::BlockStatement;
|
||||
}
|
||||
virtual FString typeName() override
|
||||
{
|
||||
return FString(u8"BlockStatement");
|
||||
}
|
||||
BlockStatementAst() { type = AstType::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
|
||||
{
|
||||
return FString(std::format("<StmtAst '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
#define __FCORE_VERSION "0.3.7-alpha"
|
||||
#define __FCORE_VERSION "0.4.2-alpha"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define __FCORE_PLATFORM "Windows"
|
||||
|
||||
21
src/Core/executablePath.hpp
Normal file
21
src/Core/executablePath.hpp
Normal 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
|
||||
18
src/Core/runtimeTime.cpp
Normal file
18
src/Core/runtimeTime.cpp
Normal 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
10
src/Core/runtimeTime.hpp
Normal 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();
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <format>
|
||||
#include <source_location>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
@@ -16,8 +17,10 @@ namespace Fig
|
||||
explicit AddressableError(FString _msg,
|
||||
size_t _line,
|
||||
size_t _column,
|
||||
FString _sourcePath,
|
||||
std::vector<FString> _sourceLines,
|
||||
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;
|
||||
}
|
||||
@@ -33,9 +36,11 @@ namespace Fig
|
||||
}
|
||||
std::source_location src_loc;
|
||||
|
||||
size_t getLine() const { return line; }
|
||||
size_t getColumn() const { return column; }
|
||||
virtual size_t getLine() const { return line; }
|
||||
virtual size_t getColumn() const { return column; }
|
||||
FString getMessage() const { return message; }
|
||||
FString getSourcePath() const { return sourcePath; }
|
||||
std::vector<FString> getSourceLines() const { return sourceLines; }
|
||||
|
||||
virtual FString getErrorType() const
|
||||
{
|
||||
@@ -45,6 +50,9 @@ namespace Fig
|
||||
protected:
|
||||
size_t line, column;
|
||||
FString message;
|
||||
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
};
|
||||
|
||||
class UnaddressableError : public std::exception
|
||||
@@ -84,14 +92,6 @@ namespace Fig
|
||||
public:
|
||||
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
|
||||
{
|
||||
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||
|
||||
@@ -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");
|
||||
namespace TC = TerminalColors;
|
||||
coloredPrint(TC::LightWhite, "An error occurred! ");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
||||
#include "Value/interface.hpp"
|
||||
#include <Value/Type.hpp>
|
||||
#include <algorithm>
|
||||
@@ -303,7 +304,7 @@ namespace Fig
|
||||
return false;
|
||||
}
|
||||
|
||||
Function getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
|
||||
Ast::InterfaceMethod getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
|
||||
{
|
||||
// O(N²)
|
||||
// SLOW
|
||||
@@ -336,15 +337,12 @@ namespace Fig
|
||||
if (method.name == functionName)
|
||||
{
|
||||
if (!method.hasDefaultBody()) assert(false);
|
||||
|
||||
return Function(
|
||||
method.paras, TypeInfo(method.returnType), method.defaultBody, shared_from_this());
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return Function(); // ignore warning
|
||||
}
|
||||
|
||||
const Function &getImplementedMethod(const TypeInfo &structType, const FString &functionName) const
|
||||
|
||||
40
src/Evaluator/Value/IntPool.hpp
Normal file
40
src/Evaluator/Value/IntPool.hpp
Normal 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
|
||||
@@ -87,7 +87,7 @@ namespace Fig
|
||||
std::format("Variable `{}` expects type `{}`, but got '{}'",
|
||||
s->name.toBasicString(),
|
||||
s->declaredType.toString().toBasicString(),
|
||||
v->getTypeInfo().toString().toBasicString())));
|
||||
prettyType(v).toBasicString())));
|
||||
}
|
||||
if (isAccessConst(s->am))
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
|
||||
@@ -75,6 +76,28 @@ namespace Fig
|
||||
using BoolClass = bool;
|
||||
using NullClass = std::monostate;
|
||||
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 Fig
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#include <Ast/AccessModifier.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Value/Type.hpp>
|
||||
#include <Value/value_forward.hpp>
|
||||
|
||||
#include <memory>
|
||||
namespace Fig
|
||||
{
|
||||
class Object;
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
|
||||
struct VariableSlot
|
||||
{
|
||||
FString name;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Value/structType.hpp"
|
||||
#include <Value/Type.hpp>
|
||||
#include <Value/value.hpp>
|
||||
#include <Context/context.hpp>
|
||||
@@ -26,9 +27,7 @@ namespace Fig
|
||||
{
|
||||
if (!typeMap.contains(_name))
|
||||
{
|
||||
throw RuntimeError(FString(std::format(
|
||||
"No type named '{}'",
|
||||
_name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("No type named '{}'", _name.toBasicString())));
|
||||
// *this = ValueType::String;
|
||||
}
|
||||
id = typeMap.at(name); // may throw
|
||||
@@ -41,10 +40,7 @@ namespace Fig
|
||||
ObjectPtr value = key.value;
|
||||
const TypeInfo &type = value->getTypeInfo();
|
||||
|
||||
if (type == ValueType::Int)
|
||||
{
|
||||
return std::hash<ValueType::IntClass>{}(value->as<ValueType::IntClass>());
|
||||
}
|
||||
if (type == ValueType::Int) { return std::hash<ValueType::IntClass>{}(value->as<ValueType::IntClass>()); }
|
||||
if (type == ValueType::Double)
|
||||
{
|
||||
return std::hash<ValueType::DoubleClass>{}(value->as<ValueType::DoubleClass>());
|
||||
@@ -61,10 +57,7 @@ namespace Fig
|
||||
{
|
||||
auto HashFields = [](std::vector<Field> fields) {
|
||||
size_t r = 0;
|
||||
for (auto &f : fields)
|
||||
{
|
||||
r += std::hash<Field>{}(f);
|
||||
}
|
||||
for (auto &f : fields) { r += std::hash<Field>{}(f); }
|
||||
return r;
|
||||
};
|
||||
const StructType &st = value->as<StructType>();
|
||||
@@ -73,19 +66,30 @@ namespace Fig
|
||||
if (type == ValueType::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);
|
||||
throw ""; // ignore warning
|
||||
}
|
||||
}
|
||||
|
||||
FString prettyType(std::shared_ptr<const Object> obj)
|
||||
TypeInfo actualType(std::shared_ptr<const Object> obj)
|
||||
{
|
||||
auto t = obj->getTypeInfo();
|
||||
if (t == ValueType::StructInstance)
|
||||
return obj->as<StructInstance>().parentType.toString();
|
||||
return t.toString();
|
||||
|
||||
// dispatch builtin struct types (like Int{}, List{} e.g...)
|
||||
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
|
||||
@@ -102,8 +106,6 @@ namespace Fig
|
||||
const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12
|
||||
const TypeInfo ValueType::InterfaceType(FString(u8"InterfaceType"), true); // id: 13
|
||||
|
||||
|
||||
|
||||
bool implements(const TypeInfo &structType, const TypeInfo &interfaceType, ContextPtr ctx)
|
||||
{
|
||||
return ctx->hasImplRegisted(structType, interfaceType);
|
||||
@@ -111,28 +113,25 @@ namespace Fig
|
||||
|
||||
bool isTypeMatch(const TypeInfo &expected, ObjectPtr obj, ContextPtr ctx)
|
||||
{
|
||||
if (expected == ValueType::Any)
|
||||
return true;
|
||||
if (expected == ValueType::Any) return true;
|
||||
|
||||
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>();
|
||||
if (si.parentType == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (implements(si.parentType, expected, ctx))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return expected == actual;
|
||||
if (si.parentType == expected) { return true; }
|
||||
if (implements(si.parentType, expected, ctx)) { return true; }
|
||||
}
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
} // namespace Fig
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <Value/Type.hpp>
|
||||
#include <Value/valueError.hpp>
|
||||
#include <Value/module.hpp>
|
||||
#include <Value/value_forward.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
@@ -31,10 +32,8 @@ namespace Fig
|
||||
static_cast<ValueType::DoubleClass>(std::numeric_limits<ValueType::IntClass>::min());
|
||||
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);
|
||||
|
||||
bool operator==(const Object &, const Object &);
|
||||
@@ -509,7 +508,7 @@ namespace Fig
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
auto result = lhs.getNumericValue() + rhs.getNumericValue();
|
||||
if (bothInt && !isNumberExceededIntLimit(result))
|
||||
if (bothInt)
|
||||
return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
@@ -526,7 +525,7 @@ namespace Fig
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
auto result = lhs.getNumericValue() - rhs.getNumericValue();
|
||||
if (bothInt && !isNumberExceededIntLimit(result))
|
||||
if (bothInt)
|
||||
return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
@@ -541,10 +540,20 @@ namespace Fig
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
auto result = lhs.getNumericValue() * rhs.getNumericValue();
|
||||
if (bothInt && !isNumberExceededIntLimit(result))
|
||||
if (bothInt)
|
||||
return Object(static_cast<ValueType::IntClass>(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)));
|
||||
}
|
||||
|
||||
@@ -559,7 +568,7 @@ namespace Fig
|
||||
throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs)));
|
||||
// bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
auto result = lhs.getNumericValue() / rnv;
|
||||
// if (bothInt && !isNumberExceededIntLimit(result))
|
||||
// if (bothInt)
|
||||
// return Object(static_cast<ValueType::IntClass>(result));
|
||||
|
||||
// int / int maybe decimals
|
||||
@@ -573,15 +582,24 @@ namespace Fig
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
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())
|
||||
{
|
||||
auto rnv = rhs.getNumericValue();
|
||||
if (rnv == 0)
|
||||
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);
|
||||
if (bothInt && !isNumberExceededIntLimit(result))
|
||||
return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs)));
|
||||
@@ -698,7 +716,7 @@ namespace Fig
|
||||
{
|
||||
bool bothInt = base.is<ValueType::IntClass>() && exp.is<ValueType::IntClass>();
|
||||
auto result = std::pow(base.getNumericValue(), exp.getNumericValue());
|
||||
if (bothInt && !isNumberExceededIntLimit(result))
|
||||
if (bothInt)
|
||||
return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
@@ -706,7 +724,6 @@ namespace Fig
|
||||
}
|
||||
};
|
||||
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
using RvObject = ObjectPtr;
|
||||
|
||||
inline bool operator==(const ValueKey &l, const ValueKey &r)
|
||||
|
||||
10
src/Evaluator/Value/value_forward.hpp
Normal file
10
src/Evaluator/Value/value_forward.hpp
Normal 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
@@ -1,6 +1,7 @@
|
||||
#include "Ast/Statements/ImplementSt.hpp"
|
||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
||||
#include "Value/Type.hpp"
|
||||
#include "Ast/Expressions/InitExpr.hpp"
|
||||
#include <Ast/Statements/ImplementSt.hpp>
|
||||
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||
#include <Value/Type.hpp>
|
||||
#include <Ast/ast.hpp>
|
||||
|
||||
#include <Context/context.hpp>
|
||||
@@ -63,12 +64,18 @@ namespace Fig
|
||||
|
||||
public:
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
|
||||
void SetSourcePath(const FString &sp)
|
||||
{
|
||||
sourcePath = sp;
|
||||
}
|
||||
|
||||
void SetSourceLines(const std::vector<FString> &sl)
|
||||
{
|
||||
sourceLines = sl;
|
||||
}
|
||||
|
||||
void SetGlobalContext(ContextPtr ctx)
|
||||
{
|
||||
assert(ctx != nullptr);
|
||||
@@ -121,7 +128,7 @@ namespace Fig
|
||||
LvObject evalLv(Ast::Expression, ContextPtr); // for access: a.b / index a[b]
|
||||
|
||||
/* Right-value eval*/
|
||||
|
||||
RvObject evalInitExpr(Ast::InitExpr, ContextPtr); // only allows evalUnary to call
|
||||
RvObject evalBinary(Ast::BinaryExpr, ContextPtr); // normal binary expr: +, -, *....
|
||||
RvObject evalUnary(Ast::UnaryExpr, ContextPtr); // unary expr
|
||||
RvObject evalTernary(Ast::TernaryExpr, ContextPtr); // ternary expr
|
||||
|
||||
@@ -10,7 +10,10 @@ namespace Fig
|
||||
public:
|
||||
FString typeName;
|
||||
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;
|
||||
line = ast->getAAI().line;
|
||||
@@ -20,8 +23,13 @@ namespace Fig
|
||||
|
||||
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()));
|
||||
line = ast->getAAI().line;
|
||||
@@ -30,13 +38,11 @@ namespace Fig
|
||||
src_loc = std::move(loc);
|
||||
|
||||
typeName = std::move(_typeName);
|
||||
|
||||
sourcePath = *ast->getAAI().sourcePath;
|
||||
sourceLines = *ast->getAAI().sourceLines;
|
||||
}
|
||||
|
||||
virtual FString getErrorType() const override
|
||||
{
|
||||
return typeName;
|
||||
}
|
||||
|
||||
|
||||
virtual FString getErrorType() const override { return typeName; }
|
||||
};
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
|
||||
*/
|
||||
|
||||
#include <Utils/argparse/argparse.hpp>
|
||||
#include <print>
|
||||
// #include <print>
|
||||
#include <fstream>
|
||||
|
||||
#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/utils.hpp>
|
||||
#include <Error/errorLog.hpp>
|
||||
#include <Core/runtimeTime.hpp>
|
||||
|
||||
static size_t addressableErrorCount = 0;
|
||||
static size_t unaddressableErrorCount = 0;
|
||||
@@ -45,6 +46,10 @@ static size_t unaddressableErrorCount = 0;
|
||||
|
||||
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());
|
||||
program.add_argument("source")
|
||||
.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>());
|
||||
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;
|
||||
// while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile)
|
||||
@@ -92,11 +99,9 @@ int main(int argc, char **argv)
|
||||
// std::println("{}", tok.toString().toBasicString());
|
||||
// }
|
||||
|
||||
Fig::Parser parser(lexer);
|
||||
Fig::Parser parser(lexer, sourcePath, sourceLines);
|
||||
std::vector<Fig::Ast::AstBase> asts;
|
||||
|
||||
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
|
||||
|
||||
try
|
||||
{
|
||||
asts = parser.parseAll();
|
||||
@@ -104,7 +109,7 @@ int main(int argc, char **argv)
|
||||
catch (const Fig::AddressableError &e)
|
||||
{
|
||||
addressableErrorCount++;
|
||||
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
|
||||
ErrorLog::logAddressableError(e);
|
||||
return 1;
|
||||
}
|
||||
catch (const Fig::UnaddressableError &e)
|
||||
@@ -129,6 +134,7 @@ int main(int argc, char **argv)
|
||||
Fig::Evaluator evaluator;
|
||||
|
||||
evaluator.SetSourcePath(sourcePath);
|
||||
evaluator.SetSourceLines(sourceLines);
|
||||
evaluator.CreateGlobalContext();
|
||||
evaluator.RegisterBuiltinsValue();
|
||||
|
||||
@@ -139,7 +145,7 @@ int main(int argc, char **argv)
|
||||
catch (const Fig::AddressableError &e)
|
||||
{
|
||||
addressableErrorCount++;
|
||||
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
|
||||
ErrorLog::logAddressableError(e);
|
||||
evaluator.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <iostream> // debug
|
||||
#endif
|
||||
|
||||
#ifndef SourceInfo
|
||||
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
||||
#endif
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
@@ -62,7 +66,10 @@ namespace Fig
|
||||
{FString(u8"["), TokenType::LeftBracket},
|
||||
{FString(u8"]"), TokenType::RightBracket},
|
||||
{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{
|
||||
{FString(u8"and"), TokenType::And},
|
||||
@@ -77,6 +84,7 @@ namespace Fig
|
||||
{FString(u8"for"), TokenType::For},
|
||||
{FString(u8"if"), TokenType::If},
|
||||
{FString(u8"else"), TokenType::Else},
|
||||
{FString(u8"new"), TokenType::New},
|
||||
{FString(u8"struct"), TokenType::Struct},
|
||||
{FString(u8"interface"), TokenType::Interface},
|
||||
{FString(u8"impl"), TokenType::Implement},
|
||||
@@ -163,7 +171,7 @@ namespace Fig
|
||||
{
|
||||
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;
|
||||
}
|
||||
next();
|
||||
@@ -200,12 +208,11 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
error = SyntaxError(FString(
|
||||
std::format(
|
||||
"Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
@@ -217,7 +224,7 @@ namespace Fig
|
||||
}
|
||||
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 Token(str, TokenType::LiteralString);
|
||||
@@ -244,7 +251,7 @@ namespace Fig
|
||||
}
|
||||
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 Token(str, TokenType::LiteralString);
|
||||
@@ -275,7 +282,7 @@ namespace Fig
|
||||
{
|
||||
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;
|
||||
}
|
||||
next();
|
||||
@@ -317,12 +324,11 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
error = SyntaxError(FString(
|
||||
std::format(
|
||||
"Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
@@ -334,7 +340,7 @@ namespace Fig
|
||||
}
|
||||
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 Token(str, TokenType::LiteralString);
|
||||
@@ -378,8 +384,10 @@ namespace Fig
|
||||
|
||||
if (numStr.ends_with(U'e'))
|
||||
{
|
||||
error = SyntaxError(
|
||||
FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
|
||||
@@ -395,8 +403,10 @@ namespace Fig
|
||||
|
||||
if (!hasDigit)
|
||||
{
|
||||
error = SyntaxError(
|
||||
FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
|
||||
@@ -407,14 +417,16 @@ namespace Fig
|
||||
{
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
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());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
bool hasDigitAfterE = false;
|
||||
@@ -427,7 +439,8 @@ namespace Fig
|
||||
{
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
continue;
|
||||
@@ -438,7 +451,8 @@ namespace Fig
|
||||
{
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
@@ -447,7 +461,8 @@ namespace Fig
|
||||
{
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
it.column());
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
@@ -472,9 +487,10 @@ namespace Fig
|
||||
|
||||
if (!startsWith(sym))
|
||||
{
|
||||
error = SyntaxError(
|
||||
FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line, it.column());
|
||||
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
next();
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -500,9 +516,10 @@ namespace Fig
|
||||
|
||||
if (!symbol_map.contains(sym))
|
||||
{
|
||||
error = SyntaxError(
|
||||
FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line, it.column());
|
||||
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
next();
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -562,7 +579,8 @@ namespace Fig
|
||||
|
||||
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();
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -633,9 +651,11 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
error = SyntaxError(FString(
|
||||
std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
||||
this->line, it.column());
|
||||
error =
|
||||
SyntaxError(FString(std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
||||
this->line,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
if (hasNext())
|
||||
{
|
||||
next();
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace Fig
|
||||
SyntaxError error;
|
||||
UTF8Iterator it;
|
||||
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
|
||||
std::vector<Warning> warnings;
|
||||
|
||||
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> keyword_map;
|
||||
|
||||
inline Lexer(const FString &_source) :
|
||||
source(_source), it(source)
|
||||
inline Lexer(const FString &_source, const FString &_sourcePath, const std::vector<FString> &_sourceLines) :
|
||||
source(_source), it(source), sourcePath(_sourcePath), sourceLines(_sourceLines)
|
||||
{
|
||||
line = 1;
|
||||
}
|
||||
|
||||
@@ -33,14 +33,14 @@ public func format(objects ...) -> Any
|
||||
{
|
||||
if objects.length() < 1
|
||||
{
|
||||
throw FormatError{"Require format string"};
|
||||
throw new FormatError{"Require format string"};
|
||||
}
|
||||
|
||||
var fmt := objects[0];
|
||||
var fmtType := value.type(fmt);
|
||||
if fmtType != "String"
|
||||
{
|
||||
throw FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
|
||||
throw new FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
|
||||
}
|
||||
|
||||
var result := "";
|
||||
@@ -56,7 +56,7 @@ public func format(objects ...) -> Any
|
||||
{
|
||||
if (i + 1 >= length)
|
||||
{
|
||||
throw FormatError{"unclosed brace"};
|
||||
throw new FormatError{"unclosed brace"};
|
||||
}
|
||||
|
||||
var nextChar = fmt[i + 1];
|
||||
@@ -80,12 +80,12 @@ public func format(objects ...) -> Any
|
||||
|
||||
if endIndex == -1
|
||||
{
|
||||
throw FormatError{"unclosed brace"};
|
||||
throw new FormatError{"unclosed brace"};
|
||||
}
|
||||
|
||||
if argIndex >= objects.length()
|
||||
{
|
||||
throw FormatError{"require enough format expression"};
|
||||
throw new FormatError{"require enough format expression"};
|
||||
}
|
||||
|
||||
result += value.string_from(objects[argIndex]);
|
||||
@@ -102,7 +102,7 @@ public func format(objects ...) -> Any
|
||||
continue;
|
||||
}
|
||||
|
||||
throw FormatError{"invalid format syntax"};
|
||||
throw new FormatError{"invalid format syntax"};
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,14 +122,14 @@ public func formatByListArgs(objects) -> Any
|
||||
}
|
||||
if objects.length() < 1
|
||||
{
|
||||
throw FormatError{"Require format string"};
|
||||
throw new FormatError{"Require format string"};
|
||||
}
|
||||
|
||||
var fmt := objects[0];
|
||||
var fmtType := value.type(fmt);
|
||||
if fmtType != "String"
|
||||
{
|
||||
throw FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
|
||||
throw new FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
|
||||
}
|
||||
|
||||
var result := "";
|
||||
@@ -145,7 +145,7 @@ if objects.length() < 1
|
||||
{
|
||||
if (i + 1 >= length)
|
||||
{
|
||||
throw FormatError{"unclosed brace"};
|
||||
throw new FormatError{"unclosed brace"};
|
||||
}
|
||||
|
||||
var nextChar = fmt[i + 1];
|
||||
@@ -169,12 +169,12 @@ if objects.length() < 1
|
||||
|
||||
if endIndex == -1
|
||||
{
|
||||
throw FormatError{"unclosed brace"};
|
||||
throw new FormatError{"unclosed brace"};
|
||||
}
|
||||
|
||||
if argIndex >= objects.length()
|
||||
{
|
||||
throw FormatError{"require enough format expression"};
|
||||
throw new FormatError{"require enough format expression"};
|
||||
}
|
||||
|
||||
result += value.string_from(objects[argIndex]);
|
||||
@@ -191,7 +191,7 @@ if objects.length() < 1
|
||||
continue;
|
||||
}
|
||||
|
||||
throw FormatError{"invalid format syntax"};
|
||||
throw new FormatError{"invalid format syntax"};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
51
src/Module/Library/std/time/time.fig
Normal file
51
src/Module/Library/std/time/time.fig
Normal 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()};
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
||||
#include "Ast/functionParameters.hpp"
|
||||
#include "Ast/Expressions/VarExpr.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 <Value/value.hpp>
|
||||
#include <Core/runtimeTime.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
@@ -33,11 +38,19 @@ namespace Fig
|
||||
{u8"true", Object::getTrueInstance()},
|
||||
{u8"false", Object::getFalseInstance()},
|
||||
{u8"Error",
|
||||
std::make_shared<Object>(InterfaceType(
|
||||
ErrorInterfaceTypeInfo,
|
||||
{Ast::InterfaceMethod(u8"toString", Ast::FunctionParameters({}, {}), u8"String", nullptr),
|
||||
Ast::InterfaceMethod(u8"getErrorClass", Ast::FunctionParameters({}, {}), u8"String", nullptr),
|
||||
Ast::InterfaceMethod(u8"getErrorMessage", Ast::FunctionParameters({}, {}), u8"String", nullptr)}))},
|
||||
std::make_shared<Object>(InterfaceType(ErrorInterfaceTypeInfo,
|
||||
{Ast::InterfaceMethod(u8"toString",
|
||||
Ast::FunctionParameters({}, {}),
|
||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||
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"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
|
||||
@@ -65,6 +78,7 @@ namespace Fig
|
||||
{u8"__fvalue_double_parse", 1},
|
||||
{u8"__fvalue_double_from", 1},
|
||||
{u8"__fvalue_string_from", 1},
|
||||
{u8"__ftime_now_ns", 0},
|
||||
/* math start */
|
||||
{u8"__fmath_acos", 1},
|
||||
{u8"__fmath_acosh", 1},
|
||||
@@ -194,6 +208,15 @@ namespace Fig
|
||||
ObjectPtr val = args[0];
|
||||
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 */
|
||||
{u8"__fmath_acos",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "Ast/Statements/ErrorFlow.hpp"
|
||||
#include "Ast/Statements/ImplementSt.hpp"
|
||||
#include "Ast/astBase.hpp"
|
||||
#include "Ast/functionParameters.hpp"
|
||||
#include "Error/error.hpp"
|
||||
#include "Token/token.hpp"
|
||||
#include <Ast/Statements/ErrorFlow.hpp>
|
||||
#include <Ast/Statements/ImplementSt.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Error/error.hpp>
|
||||
#include <Token/token.hpp>
|
||||
#include <Parser/parser.hpp>
|
||||
|
||||
namespace Fig
|
||||
@@ -22,7 +22,7 @@ namespace Fig
|
||||
// 逻辑
|
||||
{Ast::Operator::And, {5, 6}},
|
||||
{Ast::Operator::Or, {4, 5}},
|
||||
{Ast::Operator::Not, {30, 31}}, // 一元
|
||||
// {Ast::Operator::Not, {30, 31}}, // 一元
|
||||
|
||||
// 比较
|
||||
{Ast::Operator::Equal, {7, 8}},
|
||||
@@ -37,7 +37,7 @@ namespace Fig
|
||||
{Ast::Operator::BitAnd, {6, 7}},
|
||||
{Ast::Operator::BitOr, {4, 5}},
|
||||
{Ast::Operator::BitXor, {5, 6}},
|
||||
{Ast::Operator::BitNot, {30, 31}}, // 一元
|
||||
// {Ast::Operator::BitNot, {30, 31}}, // 一元
|
||||
{Ast::Operator::ShiftLeft, {15, 16}},
|
||||
{Ast::Operator::ShiftRight, {15, 16}},
|
||||
|
||||
@@ -54,17 +54,17 @@ namespace Fig
|
||||
|
||||
// // 点运算符
|
||||
// {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::Operator::BitAnd, 150}, // &
|
||||
{Ast::Operator::BitNot, 150}, // ~
|
||||
{Ast::Operator::Not, 150}, // !
|
||||
};
|
||||
|
||||
Ast::VarDef
|
||||
Parser::__parseVarDef(bool isPublic)
|
||||
Ast::VarDef Parser::__parseVarDef(bool isPublic)
|
||||
{
|
||||
// entry: current is keyword `var` or `const`
|
||||
bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
|
||||
@@ -72,31 +72,31 @@ namespace Fig
|
||||
expect(TokenType::Identifier);
|
||||
FString name = currentToken().getValue();
|
||||
next();
|
||||
FString tiName = ValueType::Any.name;
|
||||
Ast::Expression declaredType = nullptr;
|
||||
bool hasSpecificType = false;
|
||||
if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
expectPeek(TokenType::Identifier, FString(u8"Type name"));
|
||||
next();
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
next(); // consume `:`
|
||||
declaredType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
|
||||
hasSpecificType = true;
|
||||
}
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
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");
|
||||
bool followupType = false;
|
||||
|
||||
if (isThis(TokenType::Walrus))
|
||||
{
|
||||
if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
|
||||
tiName = Parser::varDefTypeFollowed;
|
||||
followupType = true;
|
||||
}
|
||||
next();
|
||||
Ast::Expression exp = parseExpression(0);
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, exp);
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, exp, followupType);
|
||||
}
|
||||
|
||||
ObjectPtr Parser::__parseValue()
|
||||
@@ -133,18 +133,12 @@ namespace Fig
|
||||
return std::make_shared<Object>(i);
|
||||
}
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralString)
|
||||
{
|
||||
return std::make_shared<Object>(_val);
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralString) { return std::make_shared<Object>(_val); }
|
||||
else if (currentToken().getType() == TokenType::LiteralBool)
|
||||
{
|
||||
return std::make_shared<Object>((_val == u8"true" ? true : false));
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull)
|
||||
{
|
||||
return Object::getNullInstance();
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull) { return Object::getNullInstance(); }
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__));
|
||||
@@ -214,7 +208,7 @@ namespace Fig
|
||||
variaPara = pname;
|
||||
next(); // skip `...`
|
||||
if (!isThis(TokenType::RightParen))
|
||||
throw SyntaxError(
|
||||
throwAddressableError<SyntaxError>(
|
||||
u8"Expects right paren, variable parameter function can only have one parameter",
|
||||
currentAAI.line,
|
||||
currentAAI.column);
|
||||
@@ -237,17 +231,17 @@ namespace Fig
|
||||
next();
|
||||
expect(TokenType::LeftParen);
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
FString retTiName = ValueType::Any.name;
|
||||
|
||||
Ast::Expression returnType;
|
||||
|
||||
if (isThis(TokenType::RightArrow)) // ->
|
||||
{
|
||||
next(); // skip `->`
|
||||
expect(TokenType::Identifier);
|
||||
retTiName = currentToken().getValue();
|
||||
next(); // skip return type
|
||||
returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
|
||||
}
|
||||
expect(TokenType::LeftBrace);
|
||||
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)
|
||||
{
|
||||
@@ -289,13 +283,11 @@ namespace Fig
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute")));
|
||||
}
|
||||
FString tiName = ValueType::Any.name;
|
||||
Ast::Expression fieldType = nullptr;
|
||||
if (isThis(TokenType::Colon))
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, u8"type name");
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
next(); // consume `:`
|
||||
fieldType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
|
||||
}
|
||||
Ast::Expression initExpr = nullptr;
|
||||
if (isThis(TokenType::Assign))
|
||||
@@ -305,7 +297,7 @@ namespace Fig
|
||||
initExpr = parseExpression(0);
|
||||
}
|
||||
expectSemicolon();
|
||||
return Ast::StructDefField(am, fieldName, tiName, initExpr);
|
||||
return Ast::StructDefField(am, fieldName, fieldType, initExpr);
|
||||
};
|
||||
std::vector<Ast::Statement> stmts;
|
||||
std::vector<Ast::StructDefField> fields;
|
||||
@@ -318,10 +310,7 @@ namespace Fig
|
||||
next(); // consume `}`
|
||||
break;
|
||||
}
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
if (isThis(TokenType::Identifier)) { fields.push_back(__parseStructField(false)); }
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
if (isNext(TokenType::Const))
|
||||
@@ -361,23 +350,18 @@ namespace Fig
|
||||
next(); // consume `struct`
|
||||
stmts.push_back(__parseStructDef(false));
|
||||
}
|
||||
else if (isThis(TokenType::Const))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
else if (isThis(TokenType::Const)) { fields.push_back(__parseStructField(false)); }
|
||||
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
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
if (!braceClosed)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString("braces are not closed"));
|
||||
}
|
||||
if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
|
||||
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
|
||||
}
|
||||
|
||||
@@ -409,31 +393,22 @@ namespace Fig
|
||||
expect(TokenType::RightArrow); // ->
|
||||
next(); // consume `->`
|
||||
|
||||
expect(TokenType::Identifier, u8"return type");
|
||||
FString returnType = currentToken().getValue();
|
||||
next(); // consume return type
|
||||
Ast::Expression returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
|
||||
|
||||
if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
Ast::BlockStatement block = __parseBlockStatement();
|
||||
|
||||
methods.push_back(Ast::InterfaceMethod(
|
||||
funcName,
|
||||
paras,
|
||||
returnType,
|
||||
block));
|
||||
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType, block));
|
||||
continue;
|
||||
}
|
||||
expectSemicolon();
|
||||
|
||||
methods.push_back(Ast::InterfaceMethod(
|
||||
funcName,
|
||||
paras,
|
||||
returnType));
|
||||
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType));
|
||||
}
|
||||
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);
|
||||
@@ -454,7 +429,7 @@ namespace Fig
|
||||
FString structName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
expect(TokenType::LeftBrace); // {
|
||||
next(); // consume `{`
|
||||
next(); // consume `{`
|
||||
|
||||
std::vector<Ast::ImplementMethod> methods;
|
||||
|
||||
@@ -473,14 +448,11 @@ namespace Fig
|
||||
Ast::FunctionParameters paras = __parseFunctionParameters();
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
methods.push_back(Ast::ImplementMethod(
|
||||
funcName,
|
||||
paras,
|
||||
body));
|
||||
methods.push_back(Ast::ImplementMethod(funcName, paras, body));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,15 +512,13 @@ namespace Fig
|
||||
hasType = true;
|
||||
}
|
||||
expect(TokenType::RightParen); // )
|
||||
next(); // consume `)`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
next(); // consume `)`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -556,7 +526,8 @@ namespace Fig
|
||||
{
|
||||
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`
|
||||
expect(TokenType::LeftBrace);
|
||||
@@ -574,17 +545,11 @@ namespace Fig
|
||||
{
|
||||
Ast::Statement stmt;
|
||||
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
|
||||
else if (isThis(TokenType::Import))
|
||||
{
|
||||
stmt = __parseImport();
|
||||
}
|
||||
else if (isThis(TokenType::Import)) { stmt = __parseImport(); }
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
next(); // consume `public`
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
stmt = __parseVarDef(true);
|
||||
}
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(true); }
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
@@ -592,21 +557,17 @@ namespace Fig
|
||||
}
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
next();
|
||||
stmt = __parseStructDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Interface))
|
||||
{
|
||||
stmt = __parseInterfaceDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
|
||||
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))
|
||||
{
|
||||
stmt = __parseVarDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(false); }
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
@@ -624,50 +585,20 @@ namespace Fig
|
||||
next();
|
||||
stmt = __parseInterfaceDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Implement))
|
||||
{
|
||||
stmt = __parseImplement();
|
||||
}
|
||||
else if (isThis(TokenType::If))
|
||||
{
|
||||
stmt = __parseIf();
|
||||
}
|
||||
else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
|
||||
else if (isThis(TokenType::If)) { stmt = __parseIf(); }
|
||||
else if (isThis(TokenType::Else))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`"));
|
||||
}
|
||||
else if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
stmt = __parseBlockStatement();
|
||||
}
|
||||
else if (isThis(TokenType::While))
|
||||
{
|
||||
stmt = __parseWhile();
|
||||
}
|
||||
else if (isThis(TokenType::For))
|
||||
{
|
||||
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 if (isThis(TokenType::LeftBrace)) { stmt = __parseBlockStatement(); }
|
||||
else if (isThis(TokenType::While)) { stmt = __parseWhile(); }
|
||||
else if (isThis(TokenType::For)) { 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 if (allowExp)
|
||||
{
|
||||
// expression statement
|
||||
@@ -677,11 +608,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SyntaxError(
|
||||
u8"invalid syntax",
|
||||
currentAAI.line,
|
||||
currentAAI.column
|
||||
);
|
||||
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
@@ -768,7 +695,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
condition = parseExpression(0);
|
||||
condition = parseExpression(0, TokenType::LeftBrace);
|
||||
}
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
@@ -786,7 +713,8 @@ namespace Fig
|
||||
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");
|
||||
}
|
||||
@@ -801,8 +729,7 @@ namespace Fig
|
||||
// TODO: support enumeration
|
||||
next(); // consume `for`
|
||||
bool paren = isThis(TokenType::LeftParen);
|
||||
if (paren)
|
||||
next(); // consume `(`
|
||||
if (paren) next(); // consume `(`
|
||||
// support 3-part for loop
|
||||
// for init; condition; increment {}
|
||||
Ast::Statement initStmt = __parseStatement(false); // auto check ``
|
||||
@@ -815,8 +742,7 @@ namespace Fig
|
||||
// auto guard = disableSemicolon();
|
||||
incrementStmt = __parseIncrementStatement();
|
||||
} // after parse increment, semicolon check state restored
|
||||
if (paren)
|
||||
expectConsume(TokenType::RightParen); // consume `)` if has `(`
|
||||
if (paren) expectConsume(TokenType::RightParen); // consume `)` if has `(`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}`
|
||||
return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body);
|
||||
@@ -940,10 +866,7 @@ namespace Fig
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon))
|
||||
{
|
||||
mode = 2;
|
||||
}
|
||||
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon)) { mode = 2; }
|
||||
else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace)))
|
||||
{
|
||||
mode = 3;
|
||||
@@ -987,17 +910,19 @@ namespace Fig
|
||||
}
|
||||
else if (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(
|
||||
std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())));
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())));
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBrace);
|
||||
next(); // consume `}`
|
||||
return makeAst<Ast::InitExprAst>(structe, args,
|
||||
(mode == 1 ? Ast::InitExprAst::InitMode::Positional :
|
||||
(mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand)));
|
||||
return makeAst<Ast::InitExprAst>(
|
||||
structe,
|
||||
args,
|
||||
static_cast<Ast::InitExprAst::InitMode>(mode));
|
||||
}
|
||||
|
||||
Ast::Expression Parser::__parseTupleOrParenExpr()
|
||||
{
|
||||
next();
|
||||
@@ -1019,8 +944,7 @@ namespace Fig
|
||||
{
|
||||
next(); // consume ','
|
||||
|
||||
if (currentToken().getType() == TokenType::RightParen)
|
||||
break;
|
||||
if (currentToken().getType() == TokenType::RightParen) break;
|
||||
|
||||
elements.push_back(parseExpression(0));
|
||||
}
|
||||
@@ -1071,10 +995,7 @@ namespace Fig
|
||||
expect(TokenType::Identifier, u8"package name");
|
||||
path.push_back(currentToken().getValue());
|
||||
next(); // consume package name
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (isThis(TokenType::Semicolon)) { break; }
|
||||
else if (isThis(TokenType::Dot))
|
||||
{
|
||||
next(); // consume `.`
|
||||
@@ -1094,8 +1015,7 @@ namespace Fig
|
||||
Ast::Operator op;
|
||||
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||
if (tok.getType() == stop || tok.getType() == stop2)
|
||||
{
|
||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
|
||||
@@ -1141,6 +1061,14 @@ namespace Fig
|
||||
next();
|
||||
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
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
|
||||
@@ -1150,21 +1078,31 @@ namespace Fig
|
||||
while (true)
|
||||
{
|
||||
tok = currentToken();
|
||||
if (tok.getType() == stop || tok.getType() == stop2|| tok == EOFTok) break;
|
||||
if (tok.getType() == stop || tok.getType() == stop2 || tok == EOFTok) break;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
lhs = __parseCall(lhs);
|
||||
continue;
|
||||
}
|
||||
// else if (tok.getType() == TokenType::LeftBrace) { lhs = __parseInitExpr(lhs); }
|
||||
/*
|
||||
since Fig v0.4.2, use new struct{};
|
||||
|
||||
if (tok.getType() == TokenType::LeftBrace)
|
||||
{
|
||||
lhs = __parseInitExpr(lhs);
|
||||
continue;
|
||||
}
|
||||
if a == A{}
|
||||
is A{} struct init?
|
||||
or A a variable, {} is the body?
|
||||
|
||||
fuck.
|
||||
*/
|
||||
|
||||
// member access: a.b
|
||||
if (tok.getType() == TokenType::Dot)
|
||||
@@ -1191,15 +1129,17 @@ namespace Fig
|
||||
lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ternary
|
||||
if (tok.getType() == TokenType::Question)
|
||||
{
|
||||
auto [lbp, rbp] = getBindingPower(Ast::Operator::TernaryCond);
|
||||
if (bp >= lbp) break;
|
||||
|
||||
next(); // consume ?
|
||||
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon, stop2);
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume :
|
||||
Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2);
|
||||
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
|
||||
expectConsume(TokenType::Colon);
|
||||
|
||||
Ast::Expression falseExpr = parseExpression(0);
|
||||
lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
|
||||
continue;
|
||||
}
|
||||
@@ -1207,11 +1147,11 @@ namespace Fig
|
||||
if (!isTokenOp(tok)) break;
|
||||
|
||||
op = Ast::TokenToOp.at(tok.getType());
|
||||
Precedence lbp = getLeftBindingPower(op);
|
||||
auto [lbp, rbp] = getBindingPower(op);
|
||||
if (bp >= lbp) break;
|
||||
|
||||
next(); // consume op
|
||||
lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp, stop, stop2));
|
||||
lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(rbp, stop, stop2));
|
||||
}
|
||||
|
||||
return lhs;
|
||||
@@ -1221,20 +1161,15 @@ namespace Fig
|
||||
{
|
||||
output.clear();
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (tok == EOFTok) { return output; }
|
||||
|
||||
while (!isEOF())
|
||||
{
|
||||
auto stmt = __parseStatement();
|
||||
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
|
||||
{
|
||||
throw SyntaxError(
|
||||
u8"Package must be at the beginning of the file",
|
||||
currentAAI.line,
|
||||
currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(
|
||||
u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
pushNode(stmt);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Ast/astBase.hpp"
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/ast.hpp>
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Error/error.hpp>
|
||||
|
||||
#include <print>
|
||||
#include <memory>
|
||||
#include <source_location>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace Fig
|
||||
std::vector<Ast::AstBase> output;
|
||||
std::vector<Token> previousTokens;
|
||||
|
||||
std::shared_ptr<FString> sourcePathPtr;
|
||||
std::shared_ptr<std::vector<FString>> sourceLinesPtr;
|
||||
|
||||
size_t tokenPruduced = 0;
|
||||
size_t currentTokenIndex = 0;
|
||||
|
||||
@@ -72,7 +75,11 @@ namespace Fig
|
||||
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
|
||||
static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
|
||||
|
||||
Parser(const Lexer &_lexer) : 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 { return error.get(); }
|
||||
|
||||
@@ -83,7 +90,7 @@ namespace Fig
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
||||
_ErrT spError(msg, line, column, loc);
|
||||
_ErrT spError(msg, line, column, *sourcePathPtr, *sourceLinesPtr, loc);
|
||||
error = std::make_unique<_ErrT>(spError);
|
||||
throw spError;
|
||||
}
|
||||
@@ -92,7 +99,7 @@ namespace Fig
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
||||
// 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);
|
||||
throw spError;
|
||||
}
|
||||
@@ -135,7 +142,10 @@ namespace Fig
|
||||
CTI也需要显示转换,否则转换完的pruduced又会被转回去,变为 int64_t max
|
||||
*/
|
||||
currentTokenIndex++;
|
||||
setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line, .column = currentToken().column});
|
||||
setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line,
|
||||
.column = currentToken().column,
|
||||
.sourcePath = sourcePathPtr,
|
||||
.sourceLines = sourceLinesPtr});
|
||||
return;
|
||||
}
|
||||
if (isEOF()) return;
|
||||
@@ -143,7 +153,11 @@ namespace Fig
|
||||
tokenPruduced++;
|
||||
if (tok == IllegalTok) throw lexer.getError();
|
||||
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);
|
||||
}
|
||||
inline const Token ¤tToken()
|
||||
@@ -233,7 +247,7 @@ namespace Fig
|
||||
|
||||
[[nodiscard]] SemicolonDisabler disableSemicolon() { 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
|
||||
|
||||
@@ -248,18 +262,18 @@ namespace Fig
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type)
|
||||
void expectConsume(TokenType type, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
expect(type);
|
||||
expect(type, loc);
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -298,9 +312,10 @@ namespace Fig
|
||||
Ast::ListExpr __parseListExpr(); // 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::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
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Fig
|
||||
For, // for
|
||||
If, // if
|
||||
Else, // else
|
||||
New, // new
|
||||
Struct, // struct
|
||||
Interface, // interface
|
||||
Implement, // impl
|
||||
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
printFString(node->name, 0);
|
||||
printIndent(indent + 2);
|
||||
std::cout << "Type: ";
|
||||
printFString(node->typeName, 0);
|
||||
printFString(node->declaredType->toString(), 0);
|
||||
if (node->expr)
|
||||
{
|
||||
printIndent(indent + 2);
|
||||
|
||||
Reference in New Issue
Block a user