添加结构体组合, interface x : a + b {}
This commit is contained in:
30
ExampleCodes/3-Structure.fig
Normal file
30
ExampleCodes/3-Structure.fig
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import std.io;
|
||||||
|
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
x: Int; // type specifiers are optional
|
||||||
|
y: Int; // type specifiers are optional
|
||||||
|
|
||||||
|
// x and y are private fields, can only reached by internal context
|
||||||
|
|
||||||
|
public func toString() -> String
|
||||||
|
{
|
||||||
|
return "(" + (x as String) + "," + (y as String) + ")";
|
||||||
|
}
|
||||||
|
// public func toString() {} is ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// make points
|
||||||
|
|
||||||
|
var p1 := new Point{1, 2};
|
||||||
|
io.println(p1.toString()); // (1,2)
|
||||||
|
|
||||||
|
var p2 := new Point{x: 2, y: 3};
|
||||||
|
io.println(p2.toString()); // (2,3)
|
||||||
|
|
||||||
|
var x := 114;
|
||||||
|
var y := 514;
|
||||||
|
|
||||||
|
var p3 := new Point{y, x}; // shorthand mode, can be unordered, auto match field and variable!
|
||||||
|
// = Point{x: x, y: y}
|
||||||
|
io.println(p3.toString()); // (114,514)
|
||||||
2
ExampleCodes/4-Interface.fig
Normal file
2
ExampleCodes/4-Interface.fig
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import std.io;
|
||||||
|
|
||||||
@@ -35,10 +35,22 @@ namespace Fig::Ast
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
interface IO : Writable + Readable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
interface XX
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
class InterfaceDefAst final : public StatementAst
|
class InterfaceDefAst final : public StatementAst
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FString name;
|
FString name;
|
||||||
|
std::vector<Expression> bundles;
|
||||||
std::vector<InterfaceMethod> methods;
|
std::vector<InterfaceMethod> methods;
|
||||||
std::vector<FString> parents; // Feature, NOT NOW
|
std::vector<FString> parents; // Feature, NOT NOW
|
||||||
bool isPublic;
|
bool isPublic;
|
||||||
@@ -48,8 +60,8 @@ namespace Fig::Ast
|
|||||||
type = AstType::InterfaceDefSt;
|
type = AstType::InterfaceDefSt;
|
||||||
}
|
}
|
||||||
|
|
||||||
InterfaceDefAst(FString _name, std::vector<InterfaceMethod> _methods, bool _isPublic) :
|
InterfaceDefAst(FString _name, std::vector<Expression> _bundles, std::vector<InterfaceMethod> _methods, bool _isPublic) :
|
||||||
name(std::move(_name)), methods(std::move(_methods)), isPublic(_isPublic)
|
name(std::move(_name)), bundles(std::move(_bundles)), methods(std::move(_methods)), isPublic(_isPublic)
|
||||||
{
|
{
|
||||||
type = AstType::InterfaceDefSt;
|
type = AstType::InterfaceDefSt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,9 +183,9 @@ namespace Fig
|
|||||||
// we've checked argument count before, so here
|
// we've checked argument count before, so here
|
||||||
// must be a default value
|
// must be a default value
|
||||||
|
|
||||||
// evaluate default value in definition context
|
// evaluate default value in definition context!
|
||||||
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
||||||
ctx)); // it can't be null here
|
defContext)); // it can't be null here
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||||
@@ -345,13 +345,12 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContextPtr stDefCtx = structT.defContext;
|
|
||||||
|
|
||||||
// load struct method
|
// load struct method
|
||||||
for (auto &[id, fn] : stDefCtx->getFunctions())
|
for (auto &[id, fn] : defContext->getFunctions())
|
||||||
{
|
{
|
||||||
const FString &funcName = fn.name;
|
const FString &funcName = fn.name;
|
||||||
const auto &funcSlot = stDefCtx->get(funcName);
|
const auto &funcSlot = defContext->get(funcName);
|
||||||
|
|
||||||
instanceCtx->def(funcName,
|
instanceCtx->def(funcName,
|
||||||
ValueType::Function,
|
ValueType::Function,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Ast/Statements/InterfaceDefSt.hpp"
|
||||||
#include <Evaluator/Core/ExprResult.hpp>
|
#include <Evaluator/Core/ExprResult.hpp>
|
||||||
#include <Ast/AccessModifier.hpp>
|
#include <Ast/AccessModifier.hpp>
|
||||||
#include <Ast/Expressions/FunctionCall.hpp>
|
#include <Ast/Expressions/FunctionCall.hpp>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
|
|
||||||
#include <Utils/utils.hpp>
|
#include <Utils/utils.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -165,6 +167,7 @@ namespace Fig
|
|||||||
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
||||||
|
|
||||||
const FString &interfaceName = ifd->name;
|
const FString &interfaceName = ifd->name;
|
||||||
|
const std::vector<Ast::Expression> &bundle_exprs = ifd->bundles;
|
||||||
|
|
||||||
if (ctx->containsInThisScope(interfaceName))
|
if (ctx->containsInThisScope(interfaceName))
|
||||||
{
|
{
|
||||||
@@ -173,11 +176,54 @@ namespace Fig
|
|||||||
std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()),
|
std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()),
|
||||||
ifd);
|
ifd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Ast::InterfaceMethod> bundle_methods;
|
||||||
|
std::unordered_map<FString, FString> cache_methods;
|
||||||
|
// K: interface method name V: method owner (interface)
|
||||||
|
for (const auto &exp : bundle_exprs)
|
||||||
|
{
|
||||||
|
ObjectPtr itf_val = check_unwrap_stres(eval(exp, ctx));
|
||||||
|
if (!itf_val->is<InterfaceType>())
|
||||||
|
{
|
||||||
|
throw EvaluatorError(
|
||||||
|
u8"TypeError",
|
||||||
|
std::format(
|
||||||
|
"Cannot bundle type '{}' that is not interface",
|
||||||
|
prettyType(itf_val).toBasicString()
|
||||||
|
),
|
||||||
|
exp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const InterfaceType &itfType = itf_val->as<InterfaceType>();
|
||||||
|
for (const auto &method : itfType.methods)
|
||||||
|
{
|
||||||
|
if (cache_methods.contains(method.name))
|
||||||
|
{
|
||||||
|
throw EvaluatorError(
|
||||||
|
u8"DuplicateInterfaceMethodError",
|
||||||
|
std::format(
|
||||||
|
"Interface `{}` has duplicate method '{}' with '{}.{}'",
|
||||||
|
itfType.type.toString().toBasicString(),
|
||||||
|
method.name.toBasicString(),
|
||||||
|
cache_methods[method.name].toBasicString(),
|
||||||
|
method.name.toBasicString()
|
||||||
|
),
|
||||||
|
ifd
|
||||||
|
);
|
||||||
|
}
|
||||||
|
cache_methods[method.name] = itfType.type.toString();
|
||||||
|
bundle_methods.push_back(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Ast::InterfaceMethod> methods(ifd->methods);
|
||||||
|
methods.insert(methods.end(), bundle_methods.begin(), bundle_methods.end());
|
||||||
|
|
||||||
TypeInfo type(interfaceName, true); // register interface
|
TypeInfo type(interfaceName, true); // register interface
|
||||||
ctx->def(interfaceName,
|
ctx->def(interfaceName,
|
||||||
type,
|
type,
|
||||||
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
||||||
std::make_shared<Object>(InterfaceType(type, ifd->methods)));
|
std::make_shared<Object>(InterfaceType(type, methods)));
|
||||||
return StatementResult::normal();
|
return StatementResult::normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -386,6 +386,29 @@ namespace Fig
|
|||||||
// entry: current is interface name
|
// entry: current is interface name
|
||||||
FString interfaceName = currentToken().getValue();
|
FString interfaceName = currentToken().getValue();
|
||||||
next(); // consume name
|
next(); // consume name
|
||||||
|
|
||||||
|
std::vector<Ast::Expression> bundles;
|
||||||
|
|
||||||
|
if (isThis(TokenType::Colon))
|
||||||
|
{
|
||||||
|
next(); // consume `:`
|
||||||
|
// parse bundle interfaces
|
||||||
|
|
||||||
|
if (isThis(TokenType::LeftBrace))
|
||||||
|
{
|
||||||
|
throwAddressableError<SyntaxError>(u8"expect interfaces to bundle");
|
||||||
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isThis(TokenType::LeftBrace)) { break; }
|
||||||
|
bundles.push_back(parseExpression(0, TokenType::Plus, TokenType::LeftBrace));
|
||||||
|
if (isThis(TokenType::Plus))
|
||||||
|
{
|
||||||
|
next(); // consume `+`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
expect(TokenType::LeftBrace); // `{
|
expect(TokenType::LeftBrace); // `{
|
||||||
next(); // consume `{`
|
next(); // consume `{`
|
||||||
|
|
||||||
@@ -427,7 +450,7 @@ namespace Fig
|
|||||||
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
|
return makeAst<Ast::InterfaceDefAst>(interfaceName, bundles, methods, isPublic);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast::Implement Parser::__parseImplement()
|
Ast::Implement Parser::__parseImplement()
|
||||||
|
|||||||
Reference in New Issue
Block a user