From 15633822a2c70edc0e93aed85f578e73f205a596 Mon Sep 17 00:00:00 2001 From: Enalye Date: Thu, 16 Apr 2020 00:38:22 +0200 Subject: [PATCH] Type aliases --- docs/index.md | 25 ++++++++ source/grimoire/compiler/data.d | 100 +++++++++++++++++++----------- source/grimoire/compiler/lexer.d | 7 ++- source/grimoire/compiler/parser.d | 40 ++++++++++-- source/grimoire/compiler/type.d | 28 +++++++-- 5 files changed, 155 insertions(+), 45 deletions(-) diff --git a/docs/index.md b/docs/index.md index 741a529..0a595fa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,6 +22,7 @@ You can easily define custom functions and types from D. - Enumerations - Classes - Channels + - Type aliases - Errors: - Error Handling @@ -824,6 +825,30 @@ Here, foo will be blocked until something is written on the channel, then it'll * * * +# Type Aliases + +A type alias allow types to be named differently, making long signatures shorter. + +```cpp +func square(int i) int { + return i * i; +}; + +type MyFunc = func(int) int; + +main { + MyFunc myFunc = &(MyFunc) square; + 10:myFunc:printl; +} +``` + +You can also declare aliases in D by calling `addTypeAlias` on your `GrData`: +```d +data.addTypeAlias("MyInt", grInt); +``` + +* * * + # Error Handling Error handling in Grimoire is done by raising/catching errors diff --git a/source/grimoire/compiler/data.d b/source/grimoire/compiler/data.d index e6784b3..c24080e 100644 --- a/source/grimoire/compiler/data.d +++ b/source/grimoire/compiler/data.d @@ -23,6 +23,8 @@ class GrData { /// They're pointer only defined by a name. \ /// Can only be used with primitives. dstring[] _foreigns; + /// Type aliases + GrTypeAliasDefinition[] _typeAliases; /// Enum types. GrEnumDefinition[] _enumTypes; /// Object types. @@ -40,31 +42,6 @@ class GrData { return grVoid; } - /// Define an opaque pointer type. - GrType addForeign(dstring name) { - bool isDeclared; - foreach(foreign; _foreigns) { - if(foreign == name) - isDeclared = true; - } - - if(!isDeclared) - _foreigns ~= name; - - GrType type = GrBaseType.foreign; - type.mangledType = name; - return type; - } - - /// Is the user-type defined ? - bool isForeign(dstring name) { - foreach(foreign; _foreigns) { - if(foreign == name) - return true; - } - return false; - } - /// Define an enum type. GrType addEnum(dstring name, dstring[] fields) { GrEnumDefinition enumDef = new GrEnumDefinition; @@ -93,6 +70,31 @@ class GrData { return stType; } + /// Define an opaque pointer type. + GrType addForeign(dstring name) { + bool isDeclared; + foreach(foreign; _foreigns) { + if(foreign == name) + isDeclared = true; + } + + if(!isDeclared) + _foreigns ~= name; + + GrType type = GrBaseType.foreign; + type.mangledType = name; + return type; + } + + /// Define an alias of another type. + GrType addTypeAlias(dstring name, GrType type) { + GrTypeAliasDefinition typeAlias = new GrTypeAliasDefinition; + typeAlias.name = name; + typeAlias.type = type; + _typeAliases ~= typeAlias; + return type; + } + /// Is the enum defined ? bool isEnum(dstring name) { foreach(enumType; _enumTypes) { @@ -102,6 +104,33 @@ class GrData { return false; } + /// Is the class defined ? + bool isClass(dstring name) { + foreach(class_; _classTypes) { + if(class_.name == name) + return true; + } + return false; + } + + /// Is the user-type defined ? + bool isForeign(dstring name) { + foreach(foreign; _foreigns) { + if(foreign == name) + return true; + } + return false; + } + + /// Is the type alias defined ? + bool isTypeAlias(dstring name) { + foreach(typeAlias; _typeAliases) { + if(typeAlias.name == name) + return true; + } + return false; + } + /// Return the enum definition. GrEnumDefinition getEnum(dstring name) { import std.conv: to; @@ -112,23 +141,24 @@ class GrData { assert(false, "Undefined enum \'" ~ to!string(name) ~ "\'"); } - /// Is the struct defined ? - bool isClass(dstring name) { + /// Return the class definition. + GrClassDefinition getClass(dstring name) { + import std.conv: to; foreach(class_; _classTypes) { if(class_.name == name) - return true; + return class_; } - return false; + assert(false, "Undefined class \'" ~ to!string(name) ~ "\'"); } - /// Return the struct definition. - GrClassDefinition getClass(dstring name) { + /// Return the type alias definition. + GrTypeAliasDefinition getTypeAlias(dstring name) { import std.conv: to; - foreach(class_; _classTypes) { - if(class_.name == name) - return class_; + foreach(typeAlias; _typeAliases) { + if(typeAlias.name == name) + return typeAlias; } - assert(false, "Undefined class_ \'" ~ to!string(name) ~ "\'"); + assert(false, "Undefined \'" ~ to!string(name) ~ "\'"); } /** diff --git a/source/grimoire/compiler/lexer.d b/source/grimoire/compiler/lexer.d index e06f7bf..637b53f 100644 --- a/source/grimoire/compiler/lexer.d +++ b/source/grimoire/compiler/lexer.d @@ -28,7 +28,7 @@ enum GrLexemeType { and, or, xor, not, increment, decrement, identifier, integer, float_, boolean, string_, - main_, event_, class_, enum_, new_, copy, send, receive, + main_, type_, event_, class_, enum_, new_, copy, send, receive, voidType, intType, floatType, boolType, stringType, arrayType, functionType, taskType, chanType, autoType, if_, unless, else_, switch_, select, case_, while_, do_, until, for_, loop, return_, self, kill, killAll, yield, break_, continue_, @@ -626,6 +626,9 @@ package final class GrLexer { case "main": lex.type = GrLexemeType.main_; break; + case "type": + lex.type = GrLexemeType.type_; + break; case "event": lex.type = GrLexemeType.event_; break; @@ -910,7 +913,7 @@ dstring grGetPrettyLexemeType(GrLexemeType operator) { "and", "or", "xor", "not", "++", "--", "identifier", "const_int", "const_float", "const_bool", "const_str", - "main", "event", "class", "enum", "new", "copy", "send", "receive", + "main", "type", "event", "class", "enum", "new", "copy", "send", "receive", "void", "int", "float", "bool", "string", "array", "var", "func", "task", "chan", "let", "if", "unless", "else", "switch", "select", "case", "while", "do", "until", "for", "loop", "return", "self", "kill", "killall", "yield", "break", "continue" diff --git a/source/grimoire/compiler/parser.d b/source/grimoire/compiler/parser.d index 7639c0c..05eb2ed 100644 --- a/source/grimoire/compiler/parser.d +++ b/source/grimoire/compiler/parser.d @@ -1513,6 +1513,7 @@ final class GrParser { case voidType: .. case arrayType: case autoType: case identifier: + case type_: skipExpression(); break; default: @@ -1544,6 +1545,9 @@ final class GrParser { break; case enum_: parseEnumDeclaration(); + break; + case type_: + parseTypeAliasDeclaration(); break; case main_: case event_: @@ -1592,6 +1596,7 @@ final class GrParser { case voidType: .. case arrayType: case autoType: case identifier: + case type_: skipExpression(); break; default: @@ -1635,6 +1640,9 @@ final class GrParser { break; } goto default; + case type_: + skipExpression(); + break; default: logError("Invalid type", "The type should be either main, func, task or struct"); } @@ -1642,6 +1650,25 @@ final class GrParser { endGlobalScope(); } + /** + Declare a new alias of a type. + */ + private void parseTypeAliasDeclaration() { + checkAdvance(); + if(get().type != GrLexemeType.identifier) + logError("Missing Identifier", "A type alias must be named"); + const dstring typeAliasName = get().svalue; + checkAdvance(); + if(get().type != GrLexemeType.assign) + logError("Missing =", "This should be an assignment"); + checkAdvance(); + GrType type = parseType(true); + if(get().type != GrLexemeType.semicolon) + logError("Missing ;", "The definition must end with a semicolon"); + + _data.addTypeAlias(typeAliasName, type); + } + private void parseEnumDeclaration() { checkAdvance(); if(get().type != GrLexemeType.identifier) @@ -1762,7 +1789,12 @@ final class GrParser { GrLexeme lex = get(); if(!lex.isType) { - if(lex.type == GrLexemeType.identifier && _data.isClass(lex.svalue)) { + if(lex.type == GrLexemeType.identifier && _data.isTypeAlias(lex.svalue)) { + currentType = _data.getTypeAlias(lex.svalue).type; + checkAdvance(); + return currentType; + } + else if(lex.type == GrLexemeType.identifier && _data.isClass(lex.svalue)) { currentType.baseType = GrBaseType.class_; currentType.mangledType = lex.svalue; checkAdvance(); @@ -2340,7 +2372,7 @@ final class GrParser { goto default; break; case identifier: - if(_data.isEnum(get().svalue) || _data.isClass(get().svalue) || _data.isForeign(get().svalue)) + if(_data.isTypeAlias(get().svalue) || _data.isEnum(get().svalue) || _data.isClass(get().svalue) || _data.isForeign(get().svalue)) parseLocalDeclaration(); else goto default; @@ -3217,7 +3249,7 @@ final class GrParser { type = parseType(); break; case identifier: - if(_data.isEnum(get().svalue) || _data.isClass(get().svalue) || _data.isForeign(get().svalue)) + if(_data.isTypeAlias(get().svalue) || _data.isEnum(get().svalue) || _data.isClass(get().svalue) || _data.isForeign(get().svalue)) type = parseType(); else isTyped = false; @@ -5063,7 +5095,7 @@ final class GrParser { else { if(hasParenthesis && get().type == GrLexemeType.rightParenthesis) advance(); - if(anonSignature.length) + if(signature.length != anonSignature.length) logError("Invalid anonymous call", "The number of parameters does not match"); } diff --git a/source/grimoire/compiler/type.d b/source/grimoire/compiler/type.d index 7974622..4fc10e5 100644 --- a/source/grimoire/compiler/type.d +++ b/source/grimoire/compiler/type.d @@ -137,11 +137,31 @@ GrType grGetForeignType(dstring name) { return type; } +/** +Define the content of a type alias. \ +Not to be confused with GrType used by the type system. +--- +type MyNewType = AnotherType; +--- +*/ +final class GrTypeAliasDefinition { + /// Identifier. + dstring name; + /// The type aliased. + GrType type; +} + /** Define the content of an enum. \ Not to be confused with GrType used by the type system. +--- +enum MyEnum { + field1; + field2; +} +--- */ -class GrEnumDefinition { +final class GrEnumDefinition { /// Identifier. dstring name; /// List of field names. @@ -172,15 +192,15 @@ class GrEnumDefinition { } /** -Define the content of an object. \ +Define the content of a class. \ Not to be confused with GrType used by the type system. --- -object MyObject { +class MyClass { // Fields } --- */ -class GrClassDefinition { +final class GrClassDefinition { /// Identifier. dstring name; /// List of field types.