diff --git a/ExampleCodes/3-Structure.fig b/ExampleCodes/3-Structure.fig new file mode 100644 index 0000000..cc929b9 --- /dev/null +++ b/ExampleCodes/3-Structure.fig @@ -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) \ No newline at end of file diff --git a/ExampleCodes/4-Interface.fig b/ExampleCodes/4-Interface.fig new file mode 100644 index 0000000..4cfc9dc --- /dev/null +++ b/ExampleCodes/4-Interface.fig @@ -0,0 +1,2 @@ +import std.io; + diff --git a/src/Ast/Statements/InterfaceDefSt.hpp b/src/Ast/Statements/InterfaceDefSt.hpp index e0fb141..67ef077 100644 --- a/src/Ast/Statements/InterfaceDefSt.hpp +++ b/src/Ast/Statements/InterfaceDefSt.hpp @@ -35,10 +35,22 @@ namespace Fig::Ast } }; + /* + interface IO : Writable + Readable + { + } + + interface XX + { + } + + */ + class InterfaceDefAst final : public StatementAst { public: FString name; + std::vector bundles; std::vector methods; std::vector parents; // Feature, NOT NOW bool isPublic; @@ -48,8 +60,8 @@ namespace Fig::Ast type = AstType::InterfaceDefSt; } - InterfaceDefAst(FString _name, std::vector _methods, bool _isPublic) : - name(std::move(_name)), methods(std::move(_methods)), isPublic(_isPublic) + InterfaceDefAst(FString _name, std::vector _bundles, std::vector _methods, bool _isPublic) : + name(std::move(_name)), bundles(std::move(_bundles)), methods(std::move(_methods)), isPublic(_isPublic) { type = AstType::InterfaceDefSt; } diff --git a/src/Evaluator/Core/EvalInitExpr.cpp b/src/Evaluator/Core/EvalInitExpr.cpp index f6acc51..03936df 100644 --- a/src/Evaluator/Core/EvalInitExpr.cpp +++ b/src/Evaluator/Core/EvalInitExpr.cpp @@ -183,9 +183,9 @@ namespace Fig // we've checked argument count before, so here // must be a default value - // evaluate default value in definition context + // evaluate default value in definition context! ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue, - ctx)); // it can't be null here + defContext)); // it can't be null here // type check if (!isTypeMatch(expectedType, defaultVal, ctx)) @@ -345,13 +345,12 @@ namespace Fig } } } - ContextPtr stDefCtx = structT.defContext; // load struct method - for (auto &[id, fn] : stDefCtx->getFunctions()) + for (auto &[id, fn] : defContext->getFunctions()) { const FString &funcName = fn.name; - const auto &funcSlot = stDefCtx->get(funcName); + const auto &funcSlot = defContext->get(funcName); instanceCtx->def(funcName, ValueType::Function, diff --git a/src/Evaluator/Core/EvalStatement.cpp b/src/Evaluator/Core/EvalStatement.cpp index e2399e0..2d2b763 100644 --- a/src/Evaluator/Core/EvalStatement.cpp +++ b/src/Evaluator/Core/EvalStatement.cpp @@ -1,3 +1,4 @@ +#include "Ast/Statements/InterfaceDefSt.hpp" #include #include #include @@ -14,6 +15,7 @@ #include #include +#include namespace Fig { @@ -165,6 +167,7 @@ namespace Fig auto ifd = std::static_pointer_cast(stmt); const FString &interfaceName = ifd->name; + const std::vector &bundle_exprs = ifd->bundles; if (ctx->containsInThisScope(interfaceName)) { @@ -173,11 +176,54 @@ namespace Fig std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()), ifd); } + + std::vector bundle_methods; + std::unordered_map 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()) + { + throw EvaluatorError( + u8"TypeError", + std::format( + "Cannot bundle type '{}' that is not interface", + prettyType(itf_val).toBasicString() + ), + exp + ); + } + const InterfaceType &itfType = itf_val->as(); + 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 methods(ifd->methods); + methods.insert(methods.end(), bundle_methods.begin(), bundle_methods.end()); + TypeInfo type(interfaceName, true); // register interface ctx->def(interfaceName, type, (ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const), - std::make_shared(InterfaceType(type, ifd->methods))); + std::make_shared(InterfaceType(type, methods))); return StatementResult::normal(); } diff --git a/src/Parser/parser.cpp b/src/Parser/parser.cpp index a750b21..e556a01 100644 --- a/src/Parser/parser.cpp +++ b/src/Parser/parser.cpp @@ -386,6 +386,29 @@ namespace Fig // entry: current is interface name FString interfaceName = currentToken().getValue(); next(); // consume name + + std::vector bundles; + + if (isThis(TokenType::Colon)) + { + next(); // consume `:` + // parse bundle interfaces + + if (isThis(TokenType::LeftBrace)) + { + throwAddressableError(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); // `{ next(); // consume `{` @@ -427,7 +450,7 @@ namespace Fig throwAddressableError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column); } } - return makeAst(interfaceName, methods, isPublic); + return makeAst(interfaceName, bundles, methods, isPublic); } Ast::Implement Parser::__parseImplement()