[VER] 0.3.3-alpha

[FEAT] interface + impl 支持! Duck Typing + 严格的检查让语言健壮
[FEAT][IMPL] 增加辅助函数 isTypeMatch等
[IMPL] TypeInfo构造函数FString 现在 explicit
This commit is contained in:
2025-12-30 12:02:27 +08:00
parent f19b14f45f
commit f58a60c8e3
15 changed files with 852 additions and 80 deletions

View File

@@ -0,0 +1,46 @@
#pragma once
#include <Ast/functionParameters.hpp>
#include <Ast/Statements/FunctionDefSt.hpp>
#include <Ast/astBase.hpp>
namespace Fig::Ast
{
/*
impl Readable for File
{
read() -> String
{
...
}
*/
struct ImplementMethod
{
FString name;
FunctionParameters paras;
BlockStatement body;
};
class ImplementAst final : public StatementAst
{
public:
FString interfaceName;
FString structName;
std::vector<ImplementMethod> methods;
ImplementAst()
{
type = AstType::ImplementSt;
}
ImplementAst(FString _interfaceName, FString _structName, std::vector<ImplementMethod> _methods) :
interfaceName(std::move(_interfaceName)), structName(std::move(_structName)), methods(std::move(_methods))
{
type = AstType::ImplementSt;
}
};
using Implement = std::shared_ptr<ImplementAst>;
};

View File

@@ -0,0 +1,59 @@
#pragma once
#include <Ast/functionParameters.hpp>
#include <Ast/astBase.hpp>
namespace Fig::Ast
{
/*
interface Readable
{
read() -> String
{
// default
}
flush() -> Null; // non-default
}
*/
struct InterfaceMethod
{
FString name;
FunctionParameters paras;
FString returnType;
BlockStatement defaultBody = nullptr; // nullptr is non-default func
bool hasDefaultBody() const
{
return defaultBody != nullptr;
}
};
class InterfaceDefAst final : public StatementAst
{
public:
FString name;
std::vector<InterfaceMethod> methods;
std::vector<FString> parents; // Feature, NOT NOW
bool isPublic;
InterfaceDefAst()
{
type = AstType::InterfaceDefSt;
}
InterfaceDefAst(FString _name, std::vector<InterfaceMethod> _methods, bool _isPublic) :
name(std::move(_name)), methods(std::move(_methods)), isPublic(_isPublic)
{
type = AstType::InterfaceDefSt;
}
};
using InterfaceDef = std::shared_ptr<InterfaceDefAst>;
};

View File

@@ -21,6 +21,7 @@
#include <Ast/Statements/IfSt.hpp>
#include <Ast/Statements/ImplementSt.hpp>
#include <Ast/Statements/ImportSt.hpp>
#include <Ast/Statements/InterfaceDefSt.hpp>
#include <Ast/Statements/FunctionDefSt.hpp>
#include <Ast/Statements/ControlSt.hpp>
#include <Ast/Statements/ExpressionStmt.hpp>

View File

@@ -44,6 +44,7 @@ namespace Fig::Ast
VarDefSt,
FunctionDefSt,
StructSt,
InterfaceDefSt,
ImplementSt,
IfSt,

View File

@@ -4,6 +4,8 @@
#include <Value/Type.hpp>
#include <Core/fig_string.hpp>
#include <format>
namespace Fig::Ast
{
struct FunctionParameters // for define
@@ -26,7 +28,6 @@ namespace Fig::Ast
FunctionParameters()
{
}
FunctionParameters(PosParasType _posParas, DefParasType _defParas)
{
@@ -43,5 +44,52 @@ namespace Fig::Ast
{
return posParas.size() + defParas.size();
}
bool operator==(const FunctionParameters &other) const
{
return posParas == other.posParas && defParas == other.defParas && variadicPara == other.variadicPara && variadic == other.variadic;
}
FString toString() const
{
if (variadic)
{
return FString(variadicPara + u8"...");
}
static const auto posParasToString = [this]() {
FString out;
for (auto &p : posParas)
{
out += p.first;
if (!p.second.empty())
{
out += FString(u8":" + p.second);
}
out += u8",";
}
out.pop_back();
return out;
};
}
static const auto defParasToString = [this]() {
FString out;
for (auto &p : defParas)
{
out += p.first;
if (!p.second.first.empty())
{
out += FString(u8":" + p.second.first);
}
if (p.second.second != nullptr)
{
out += u8"=";
out += p.second.second->toString();
}
out += u8",";
}
out.pop_back();
return out;
};
return FString(std::format("{},{}", posParasToString().toBasicString(), defParasToString().toBasicString()));
}
};
} // namespace Fig::Ast

View File

@@ -1,5 +1,8 @@
#pragma once
#include "Value/interface.hpp"
#include <Value/Type.hpp>
#include <algorithm>
#include <unordered_map>
#include <iostream>
#include <memory>
@@ -12,6 +15,14 @@
namespace Fig
{
struct ImplRecord
{
TypeInfo interfaceType;
TypeInfo structType;
std::unordered_map<FString, Function> implMethods;
};
class Context : public std::enable_shared_from_this<Context>
{
private:
@@ -20,7 +31,9 @@ namespace Fig
std::unordered_map<std::size_t, Function> functions;
std::unordered_map<std::size_t, FString> functionNames;
// std::unordered_map<std::size_t, FString> structTypeNames;
// implRegistry <Struct, ordered list of ImplRecord>
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
public:
ContextPtr parent;
@@ -49,6 +62,7 @@ namespace Fig
variables.insert(c.variables.begin(), c.variables.end());
functions.insert(c.functions.begin(), c.functions.end());
functionNames.insert(c.functionNames.begin(), c.functionNames.end());
implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end());
// structTypeNames.insert(c.structTypeNames.begin(), c.structTypeNames.end());
}
@@ -243,6 +257,169 @@ namespace Fig
}
return false;
}
bool hasImplRegisted(const TypeInfo &structType, const TypeInfo &interfaceType) const
{
auto it = implRegistry.find(structType);
if (it != implRegistry.end())
{
for (auto &r : it->second)
{
if (r.interfaceType == interfaceType)
return true;
}
}
return parent && parent->hasImplRegisted(structType, interfaceType);
}
std::optional<ImplRecord> getImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType) const
{
auto it = implRegistry.find(structType);
if (it != implRegistry.end())
{
for (auto &r : it->second)
{
if (r.interfaceType == interfaceType)
return r;
}
}
if (parent)
return parent->getImplRecord(structType, interfaceType);
return std::nullopt;
}
void setImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType, const ImplRecord &record)
{
auto &list = implRegistry[structType];
for (auto &r : list)
{
if (r.interfaceType == interfaceType)
return;
}
list.push_back(record); // order is the level
}
bool hasMethodImplemented(const TypeInfo &structType, const FString &functionName) const
{
auto it = implRegistry.find(structType);
if (it == implRegistry.end())
return false;
for (auto &record : it->second)
{
if (record.implMethods.contains(functionName))
return true;
}
return false;
}
bool hasDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName) const
{
auto it = implRegistry.find(structType);
if (it == implRegistry.end())
return false;
std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second)
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables)
{
if (!slot->value->is<InterfaceType>())
continue;
InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented =
std::any_of(
implementedInterfaces.begin(),
implementedInterfaces.end(),
[&](const TypeInfo &ti) { return ti == interface.type; });
if (!implemented)
continue;
for (auto &method : interface.methods)
{
if (method.name == functionName && method.hasDefaultBody())
return true;
}
}
return false;
}
Function getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
{
// O(N²)
// SLOW
// wwww (sad)
// huh
// just let it be SLOW
// i dont give a fuck
auto it = implRegistry.find(structType);
if (it == implRegistry.end())
assert(false);
std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second)
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables)
{
if (!slot->value->is<InterfaceType>())
continue;
InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented =
std::any_of(
implementedInterfaces.begin(),
implementedInterfaces.end(),
[&](const TypeInfo &ti) { return ti == interface.type; });
if (!implemented)
continue;
for (auto &method : interface.methods)
{
if (method.name == functionName)
{
if (!method.hasDefaultBody())
assert(false);
return Function(
method.paras,
TypeInfo(method.returnType),
method.defaultBody,
shared_from_this());
}
}
}
assert(false);
}
const Function &getImplementedMethod(const TypeInfo &structType, const FString &functionName) const
{
const auto &list = implRegistry.at(structType);
for (auto &record : list)
{
auto it = record.implMethods.find(functionName);
if (it != record.implMethods.end())
return it->second;
}
assert(false);
}
void printStackTrace(std::ostream &os = std::cerr, int indent = 0) const
{
const Context *ctx = this;

View File

@@ -1,3 +1,14 @@
#include "Value/VariableSlot.hpp"
#include "Value/value.hpp"
#include <Ast/AccessModifier.hpp>
#include <Ast/Statements/ImplementSt.hpp>
#include <Ast/Statements/InterfaceDefSt.hpp>
#include <Ast/astBase.hpp>
#include <Context/context_forward.hpp>
#include <Error/error.hpp>
#include <Value/Type.hpp>
#include <Value/interface.hpp>
#include <Value/structInstance.hpp>
#include <Error/errorLog.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
@@ -8,21 +19,14 @@
#include <filesystem>
#include <fstream>
#include <memory>
namespace Fig
{
bool Evaluator::isTypeMatch(const TypeInfo &expected, ObjectPtr obj)
bool Evaluator::isInterfaceSignatureMatch(const Ast::ImplementMethod &implMethod, const Ast::InterfaceMethod &ifMethod)
{
if (expected == ValueType::Any)
return true;
TypeInfo actual = obj->getTypeInfo();
if (actual != ValueType::StructInstance)
return expected == actual;
const StructInstance &si = obj->as<StructInstance>();
return si.parentType == expected;
return implMethod.name == ifMethod.name && implMethod.paras == ifMethod.paras;
}
LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
@@ -32,7 +36,7 @@ namespace Fig
{
throw EvaluatorError(u8"UndeclaredIdentifierError", name, var);
}
return LvObject(ctx->get(name));
return LvObject(ctx->get(name), ctx);
}
LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
{
@@ -45,7 +49,8 @@ namespace Fig
if (mod.ctx->contains(member) && mod.ctx->isVariablePublic(member))
{
return LvObject(
mod.ctx->get(member));
mod.ctx->get(member),
ctx);
}
else
{
@@ -67,7 +72,8 @@ namespace Fig
baseVal->getMemberFunction(member),
baseVal->getMemberFunctionParaCount(member))),
ValueType::Function,
AccessModifier::PublicConst)); // fake l-value
AccessModifier::PublicConst),
ctx); // fake l-value
}
if (baseVal->getTypeInfo() != ValueType::StructInstance) // and not member function found
{
@@ -80,17 +86,40 @@ namespace Fig
me->base);
}
const StructInstance &si = baseVal->as<StructInstance>();
if (!si.localContext->containsInThisScope(member) || !si.localContext->isVariablePublic(member))
if (ctx->hasMethodImplemented(si.parentType, member))
{
return LvObject(std::make_shared<VariableSlot>(
member,
std::make_shared<Object>(
ctx->getImplementedMethod(si.parentType, member)),
ValueType::Function,
AccessModifier::PublicConst),
ctx);
}
else if (si.localContext->containsInThisScope(member) && si.localContext->isVariablePublic(member))
{
return LvObject(si.localContext->get(member), ctx);
}
else if (ctx->hasDefaultImplementedMethod(si.parentType, member))
{
return LvObject(std::make_shared<VariableSlot>(
member,
std::make_shared<Object>(
ctx->getDefaultImplementedMethod(si.parentType, member)),
ValueType::Function,
AccessModifier::PublicConst),
ctx);
}
else
{
throw EvaluatorError(
u8"NoAttributeError",
std::format(
"`{}` has not attribute '{}'",
"`{}` has not attribute '{}' and no interfaces have been implemented it",
baseVal->toString().toBasicString(),
member.toBasicString()),
me->base);
}
return LvObject(si.localContext->get(member));
}
LvObject Evaluator::evalIndexExpr(Ast::IndexExpr ie, ContextPtr ctx)
{
@@ -125,14 +154,16 @@ namespace Fig
return LvObject(
base.get(),
indexVal,
LvObject::Kind::ListElement);
LvObject::Kind::ListElement,
ctx);
}
else if (type == ValueType::Map)
{
return LvObject(
base.get(),
index,
LvObject::Kind::MapElement);
LvObject::Kind::MapElement,
ctx);
}
else if (type == ValueType::String)
{
@@ -160,7 +191,8 @@ namespace Fig
return LvObject(
base.get(),
indexVal,
LvObject::Kind::StringElement);
LvObject::Kind::StringElement,
ctx);
}
else
{
@@ -450,7 +482,7 @@ namespace Fig
TypeInfo expectedType(fnParas.posParas[i].second); // look up type info, if exists a type with the name, use it, else throw
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
TypeInfo actualType = argVal->getTypeInfo();
if (!isTypeMatch(expectedType, argVal))
if (!isTypeMatch(expectedType, argVal, ctx))
{
throw EvaluatorError(
u8"ArgumentTypeMismatchError",
@@ -467,10 +499,10 @@ namespace Fig
for (; i < fnArgs.getLength(); i++)
{
size_t defParamIndex = i - fnParas.posParas.size();
TypeInfo expectedType = fnParas.defParas[defParamIndex].second.first;
TypeInfo expectedType(fnParas.defParas[defParamIndex].second.first);
ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second, ctx);
if (!isTypeMatch(expectedType, defaultVal))
if (!isTypeMatch(expectedType, defaultVal, ctx))
{
throw EvaluatorError(
u8"DefaultParameterTypeError",
@@ -484,7 +516,7 @@ namespace Fig
ObjectPtr argVal = eval(fnArgs.argv[i], ctx);
TypeInfo actualType = argVal->getTypeInfo();
if (!isTypeMatch(expectedType, argVal))
if (!isTypeMatch(expectedType, argVal, ctx))
{
throw EvaluatorError(
u8"ArgumentTypeMismatchError",
@@ -512,13 +544,13 @@ namespace Fig
if (j < fnParas.posParas.size())
{
paramName = fnParas.posParas[j].first;
paramType = fnParas.posParas[j].second;
paramType = TypeInfo(fnParas.posParas[j].second);
}
else
{
size_t defParamIndex = j - fnParas.posParas.size();
paramName = fnParas.defParas[defParamIndex].first;
paramType = fnParas.defParas[defParamIndex].second.first;
paramType = TypeInfo(fnParas.defParas[defParamIndex].second.first);
}
AccessModifier argAm = AccessModifier::Const;
newContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]);
@@ -553,7 +585,7 @@ namespace Fig
break;
}
}
if (!isTypeMatch(fnStruct.retType, retVal))
if (!isTypeMatch(fnStruct.retType, retVal, ctx))
{
throw EvaluatorError(
u8"ReturnTypeMismatchError",
@@ -741,7 +773,7 @@ namespace Fig
ObjectPtr defaultVal = eval(field.defaultValue, ctx); // it can't be null here
// type check
if (!isTypeMatch(expectedType, defaultVal))
if (!isTypeMatch(expectedType, defaultVal, ctx))
{
throw EvaluatorError(
u8"StructFieldTypeMismatchError",
@@ -759,7 +791,7 @@ namespace Fig
}
const ObjectPtr &argVal = evaluatedArgs[i].second;
if (!isTypeMatch(expectedType, argVal))
if (!isTypeMatch(expectedType, argVal, ctx))
{
throw EvaluatorError(
u8"StructFieldTypeMismatchError",
@@ -797,7 +829,7 @@ namespace Fig
// type check
const TypeInfo &expectedType = field.type;
if (!isTypeMatch(expectedType, defaultVal))
if (!isTypeMatch(expectedType, defaultVal, ctx))
{
throw EvaluatorError(
u8"StructFieldTypeMismatchError",
@@ -814,7 +846,7 @@ namespace Fig
continue;
}
const ObjectPtr &argVal = evaluatedArgs[i].second;
if (!isTypeMatch(field.type, argVal))
if (!isTypeMatch(field.type, argVal, ctx))
{
throw EvaluatorError(
u8"StructFieldTypeMismatchError",
@@ -918,7 +950,7 @@ namespace Fig
else if (!declaredTypeName.empty())
{
declaredType = TypeInfo(declaredTypeName);
if (value != nullptr && !isTypeMatch(declaredType, value))
if (value != nullptr && !isTypeMatch(declaredType, value, ctx))
{
throw EvaluatorError(
u8"TypeError",
@@ -1031,6 +1063,194 @@ namespace Fig
return StatementResult::normal();
}
case InterfaceDefSt: {
auto ifd = std::dynamic_pointer_cast<Ast::InterfaceDefAst>(stmt);
assert(ifd != nullptr);
const FString &interfaceName = ifd->name;
if (ctx->containsInThisScope(interfaceName))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format("Interface `{}` already declared in this scope",
interfaceName.toBasicString()),
ifd);
}
TypeInfo type(interfaceName, true); // register interface
ctx->def(
interfaceName,
type,
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
std::make_shared<Object>(InterfaceType(
type,
ifd->methods)));
return StatementResult::normal();
}
case ImplementSt: {
auto ip = std::dynamic_pointer_cast<Ast::ImplementAst>(stmt);
assert(ip != nullptr);
TypeInfo structType(ip->structName);
TypeInfo interfaceType(ip->interfaceName);
if (ctx->hasImplRegisted(structType, interfaceType))
{
throw EvaluatorError(
u8"DuplicateImplError",
std::format(
"Duplicate implement `{}` for `{}`",
interfaceType.toString().toBasicString(),
structType.toString().toBasicString()),
ip);
}
if (!ctx->contains(ip->interfaceName))
{
throw EvaluatorError(
u8"InterfaceNotFoundError",
std::format("Interface '{}' not found", ip->interfaceName.toBasicString()),
ip);
}
if (!ctx->contains(ip->structName))
{
throw EvaluatorError(
u8"StructNotFoundError",
std::format("Struct '{}' not found", ip->structName.toBasicString()),
ip);
}
auto interfaceSlot = ctx->get(ip->interfaceName);
auto structSlot = ctx->get(ip->structName);
LvObject interfaceLv(interfaceSlot, ctx);
LvObject structLv(structSlot, ctx);
ObjectPtr interfaceObj = interfaceLv.get();
ObjectPtr structTypeObj = structLv.get();
if (!interfaceObj->is<InterfaceType>())
{
throw EvaluatorError(
u8"NotAInterfaceError",
std::format("Variable `{}` is not a interface", ip->interfaceName.toBasicString()),
ip);
}
if (!structTypeObj->is<StructType>())
{
throw EvaluatorError(
u8"NotAStructType",
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
ip);
}
auto &implementMethods = ip->methods;
InterfaceType &interface = interfaceObj->as<InterfaceType>();
// ===== interface implementation validation =====
ImplRecord record{interfaceType, structType, {}};
std::unordered_map<FString, Ast::InterfaceMethod> ifaceMethods;
for (auto &m : interface.methods)
{
if (ifaceMethods.contains(m.name))
{
throw EvaluatorError(
u8"InterfaceDuplicateMethodError",
std::format("Interface '{}' has duplicate method '{}'",
interfaceType.toString().toBasicString(),
m.name.toBasicString()),
ip);
}
ifaceMethods[m.name] = m;
}
std::unordered_set<FString> implemented;
for (auto &implMethod : implementMethods)
{
const FString &name = implMethod.name;
// ---- redundant impl ----
if (!ifaceMethods.contains(name))
{
throw EvaluatorError(
u8"RedundantImplementationError",
std::format("Struct '{}' implements extra method '{}' "
"which is not required by interface '{}'",
structType.toString().toBasicString(),
name.toBasicString(),
interfaceType.toString().toBasicString()),
ip);
}
if (implemented.contains(name))
{
throw EvaluatorError(
u8"DuplicateImplementMethodError",
std::format("Duplicate implement method '{}'",
name.toBasicString()),
ip);
}
auto &ifMethod = ifaceMethods[name];
// ---- signature check ----
if (!isInterfaceSignatureMatch(implMethod, ifMethod))
{
throw EvaluatorError(
u8"InterfaceSignatureMismatch",
std::format(
"Interface method '{}({})' signature mismatch with "
"implementation '{}({})'",
ifMethod.name.toBasicString(),
ifMethod.paras.toString().toBasicString(),
implMethod.name.toBasicString(),
implMethod.paras.toString().toBasicString()),
ip);
}
if (ctx->hasMethodImplemented(structType, name))
{
throw EvaluatorError(
u8"DuplicateImplementMethodError",
std::format(
"Method '{}' already implemented by another interface "
"for struct '{}'",
name.toBasicString(),
structType.toString().toBasicString()),
ip);
}
implemented.insert(name);
record.implMethods[name] = Function(
implMethod.paras,
TypeInfo(ifMethod.returnType),
implMethod.body,
ctx);
}
for (auto &m : interface.methods)
{
if (implemented.contains(m.name))
continue;
if (m.hasDefaultBody())
continue;
throw EvaluatorError(
u8"MissingImplementationError",
std::format(
"Struct '{}' does not implement required interface method '{}' "
"and interface '{}' provides no default implementation",
structType.toString().toBasicString(),
m.name.toBasicString(),
interfaceType.toString().toBasicString()),
ip);
}
ctx->setImplRecord(structType, interfaceType, record);
return StatementResult::normal();
}
case IfSt: {
auto ifSt = std::dynamic_pointer_cast<Ast::IfSt>(stmt);
ObjectPtr condVal = eval(ifSt->condition, ctx);

View File

@@ -1,3 +1,6 @@
#include "Ast/Statements/ImplementSt.hpp"
#include "Ast/Statements/InterfaceDefSt.hpp"
#include "Value/Type.hpp"
#include <Ast/ast.hpp>
#include <Context/context.hpp>
@@ -102,7 +105,7 @@ namespace Fig
}
}
bool isTypeMatch(const TypeInfo &, ObjectPtr);
bool isInterfaceSignatureMatch(const Ast::ImplementMethod &, const Ast::InterfaceMethod &);
/* Left-value eval*/
LvObject evalVarExpr(Ast::VarExpr, ContextPtr);

View File

@@ -1,3 +1,8 @@
#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
@@ -365,6 +370,114 @@ namespace Fig
}
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
}
Ast::InterfaceDef Parser::__parseInterfaceDef(bool isPublic)
{
// entry: current is interface name
FString interfaceName = currentToken().getValue();
next(); // consume name
expect(TokenType::LeftBrace); // `{
next(); // consume `{`
std::vector<Ast::InterfaceMethod> methods;
while (true)
{
if (isThis(TokenType::RightBrace))
{
next(); // consume `}`
break;
}
if (isThis(TokenType::Identifier))
{
FString funcName = currentToken().getValue();
next(); // consume func name
expect(TokenType::LeftParen);
Ast::FunctionParameters paras = __parseFunctionParameters();
expect(TokenType::RightArrow); // ->
next(); // consume `->`
expect(TokenType::Identifier, u8"return type");
FString returnType = currentToken().getValue();
next(); // consume return type
if (isThis(TokenType::LeftBrace))
{
Ast::BlockStatement block = __parseBlockStatement();
methods.push_back(Ast::InterfaceMethod(
funcName,
paras,
returnType,
block));
continue;
}
expect(TokenType::Semicolon);
next(); // consume `;`
methods.push_back(Ast::InterfaceMethod(
funcName,
paras,
returnType));
}
else
{
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
}
}
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
}
Ast::Implement Parser::__parseImplement()
{
// entry: current is `impl`
next(); // consume `impl`
expect(TokenType::Identifier, u8"interface name");
FString interfaceName = currentToken().getValue();
next(); // consume interface name
expect(TokenType::For);
next(); // consume `for`
expect(TokenType::Identifier, u8"struct name");
FString structName = currentToken().getValue();
next(); // consume name
expect(TokenType::LeftBrace); // {
next(); // consume `{`
std::vector<Ast::ImplementMethod> methods;
while (true)
{
if (isThis(TokenType::RightBrace))
{
next(); // consume `}`
break;
}
if (isThis(TokenType::Identifier))
{
FString funcName = currentToken().getValue();
next(); // consume func name
expect(TokenType::LeftParen);
Ast::FunctionParameters paras = __parseFunctionParameters();
expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement();
methods.push_back(Ast::ImplementMethod(
funcName,
paras,
body));
}
else
{
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
}
}
return makeAst<Ast::ImplementAst>(interfaceName, structName, methods);
}
Ast::Statement Parser::__parseStatement()
{
Ast::Statement stmt;
@@ -389,9 +502,13 @@ namespace Fig
{
stmt = __parseStructDef(true);
}
else if (isThis(TokenType::Interface))
{
stmt = __parseInterfaceDef(true);
}
else
{
throwAddressableError<SyntaxError>(FString(u8"Expected `var`, `const`, `function` or `struct` after `public`"));
throwAddressableError<SyntaxError>(FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
}
}
else if (isThis(TokenType::Variable) || isThis(TokenType::Const))
@@ -409,6 +526,16 @@ namespace Fig
next();
stmt = __parseStructDef(false);
}
else if (isThis(TokenType::Interface))
{
expectPeek(TokenType::Identifier, u8"interface name");
next();
stmt = __parseInterfaceDef(false);
}
else if (isThis(TokenType::Implement))
{
stmt = __parseImplement();
}
else if (isThis(TokenType::If))
{
stmt = __parseIf();

View File

@@ -313,6 +313,8 @@ namespace Fig
Ast::VarExpr __parseVarExpr(FString);
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::InterfaceDef __parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool)
Ast::Implement __parseImplement(); // entry: current is `impl`
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);

View File

@@ -22,18 +22,20 @@ namespace Fig
ObjectPtr mapIndex;
LvObject(std::shared_ptr<VariableSlot> _slot) :
slot(std::move(_slot))
ContextPtr ctx;
LvObject(std::shared_ptr<VariableSlot> _slot, ContextPtr _ctx) :
slot(std::move(_slot)), ctx(_ctx)
{
kind = Kind::Variable;
}
LvObject(ObjectPtr _v, size_t _index, Kind _kind) :
value(_v), numIndex(_index)
LvObject(ObjectPtr _v, size_t _index, Kind _kind, ContextPtr _ctx) :
value(_v), numIndex(_index), ctx(_ctx)
{
kind = _kind;
}
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind) :
value(_v), mapIndex(_index)
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind, ContextPtr _ctx) :
value(_v), mapIndex(_index), ctx(_ctx)
{
kind = _kind;
}
@@ -78,7 +80,7 @@ namespace Fig
if (kind == Kind::Variable)
{
auto s = resolve(slot);
if (s->declaredType != ValueType::Any && s->declaredType != v->getTypeInfo())
if (!isTypeMatch(s->declaredType, v, ctx))
{
throw RuntimeError(
FString(

View File

@@ -35,7 +35,7 @@ namespace Fig
}
TypeInfo();
TypeInfo(FString _name, bool reg = false);
explicit TypeInfo(const FString &_name, bool reg = false);
TypeInfo(const TypeInfo &other) = default;
bool operator==(const TypeInfo &other) const
@@ -68,7 +68,7 @@ namespace Fig
extern const TypeInfo List;
extern const TypeInfo Map;
extern const TypeInfo Module;
// extern const TypeInfo Tuple;
extern const TypeInfo InterfaceType;
using IntClass = int64_t;
using DoubleClass = double;

20
src/Value/interface.hpp Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include <Ast/Statements/InterfaceDefSt.hpp>
#include <Value/Type.hpp>
#include <vector>
namespace Fig
{
struct InterfaceType
{
TypeInfo type;
std::vector<Ast::InterfaceMethod> methods;
bool operator==(const InterfaceType &other) const
{
return type == other.type; // only compare type info (chain -> typeinfo.id)
}
};
}

View File

@@ -1,3 +1,4 @@
#include "Value/Type.hpp"
#include <Value/value.hpp>
#include <Context/context.hpp>
@@ -8,11 +9,13 @@ namespace Fig
std::map<FString, size_t> TypeInfo::typeMap = {};
TypeInfo::TypeInfo() : // only allow use in evaluate time !! <---- dynamic type system requirement
id(1), name(FString(u8"Any")) {}
TypeInfo::TypeInfo(FString _name, bool reg)
id(1), name(FString(u8"Any"))
{
}
TypeInfo::TypeInfo(const FString &_name, bool reg)
{
static size_t id_count = 0;
name = std::move(_name);
name = _name;
// std::cerr << "TypeInfo constructor called for type name: " << name.toBasicString() << "\n";
if (reg)
{
@@ -21,6 +24,13 @@ namespace Fig
}
else
{
if (!typeMap.contains(_name))
{
throw RuntimeError(FString(std::format(
"No type named '{}'",
_name.toBasicString())));
// *this = ValueType::String;
}
id = typeMap.at(name); // may throw
}
}
@@ -69,7 +79,7 @@ namespace Fig
}
}
FString prettyType(ObjectPtr obj)
FString prettyType(std::shared_ptr<const Object> obj)
{
auto t = obj->getTypeInfo();
if (t == ValueType::StructInstance)
@@ -89,4 +99,39 @@ namespace Fig
const TypeInfo ValueType::List(FString(u8"List"), true); // id: 10
const TypeInfo ValueType::Map(FString(u8"Map"), true); // id: 11
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);
}
bool isTypeMatch(const TypeInfo &expected, ObjectPtr obj, ContextPtr ctx)
{
if (expected == ValueType::Any)
return true;
TypeInfo actual = obj->getTypeInfo();
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;
}
}
} // namespace Fig

View File

@@ -1,11 +1,13 @@
#pragma once
#include <Value/function.hpp>
#include <Value/interface.hpp>
#include <Value/structType.hpp>
#include <Value/structInstance.hpp>
#include <Value/Type.hpp>
#include <Value/valueError.hpp>
#include <Value/module.hpp>
#include <memory>
#include <variant>
#include <cmath>
#include <string>
@@ -33,7 +35,7 @@ namespace Fig
using ObjectPtr = std::shared_ptr<Object>;
using List = std::vector<ObjectPtr>;
FString prettyType(ObjectPtr obj);
FString prettyType(std::shared_ptr<const Object> obj);
struct ValueKey
{
@@ -48,7 +50,10 @@ namespace Fig
};
using Map = std::unordered_map<ValueKey, ObjectPtr, ValueKeyHash>;
class Object
bool isTypeMatch(const TypeInfo &, ObjectPtr, ContextPtr);
bool implements(const TypeInfo &, const TypeInfo &, ContextPtr);
class Object : public std::enable_shared_from_this<Object>
{
public:
using VariantType = std::variant<
@@ -62,7 +67,8 @@ namespace Fig
StructInstance,
List,
Map,
Module>;
Module,
InterfaceType>;
std::unordered_map<TypeInfo,
std::unordered_map<FString,
@@ -207,7 +213,9 @@ namespace Fig
map.contains(index));
}},
}},
{ValueType::Module, {}}};
{ValueType::Module, {}},
{ValueType::InterfaceType, {}},
};
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
{ValueType::Null, {}},
{ValueType::Int, {}},
@@ -226,8 +234,8 @@ namespace Fig
{u8"get", 1},
{u8"contains", 1},
}},
{ValueType::Module, {}}
{ValueType::Module, {}},
{ValueType::InterfaceType, {}},
};
bool hasMemberFunction(const FString &name) const
{
@@ -268,6 +276,8 @@ namespace Fig
data(m) {}
Object(const Module &m) :
data(m) {}
Object(const InterfaceType &i) :
data(i) {}
Object(const Object &) = default;
Object(Object &&) noexcept = default;
@@ -364,6 +374,9 @@ namespace Fig
else if constexpr (std::is_same_v<T, Module>)
return ValueType::Module;
else if constexpr (std::is_same_v<T, InterfaceType>)
return ValueType::InterfaceType;
else
return ValueType::Any;
},
@@ -397,11 +410,11 @@ namespace Fig
if (is<ValueType::StringClass>()) return FString(u8"<String \"") + as<ValueType::StringClass>() + FString(u8"\" >");
if (is<ValueType::BoolClass>()) return as<ValueType::BoolClass>() ? FString(u8"true") : FString(u8"false");
if (is<Function>())
return FString(std::format("<Function {} at {:p}>",
return FString(std::format("<Function '{}' at {:p}>",
as<Function>().id,
static_cast<const void *>(&as<Function>())));
if (is<StructType>())
return FString(std::format("<StructType {} at {:p}>",
return FString(std::format("<StructType '{}' at {:p}>",
as<StructType>().type.toString().toBasicString(),
static_cast<const void *>(&as<StructType>())));
if (is<StructInstance>())
@@ -441,9 +454,17 @@ namespace Fig
if (is<Module>())
{
return FString(std::format(
"<Module at {:p}>",
"<Module '{}' at {:p}>",
as<Module>().name.toBasicString(),
static_cast<const void *>(&as<Module>())));
}
if (is<InterfaceType>())
{
return FString(std::format(
"<InterfaceType '{}' at {:p}",
as<InterfaceType>().type.toString().toBasicString(),
static_cast<const void *>(&as<InterfaceType>())));
}
return FString(u8"<error>");
}