├── gradle.properties ├── src └── main │ └── kotlin │ ├── script.zc │ ├── com │ └── light672 │ │ └── zinc │ │ ├── hir │ │ ├── GenericArgs.kt │ │ ├── TypeParamBounds.kt │ │ ├── WhereClause.kt │ │ ├── Type.kt │ │ ├── TypeItemRef.kt │ │ ├── Pattern.kt │ │ ├── ValueItemRef.kt │ │ ├── Stmt.kt │ │ ├── Expr.kt │ │ └── Resolver.kt │ │ ├── dsr │ │ ├── Branch.kt │ │ ├── GenericParams.kt │ │ ├── Pattern.kt │ │ ├── Item.kt │ │ ├── Stmt.kt │ │ ├── Expr.kt │ │ └── ASTContextualizer.kt │ │ ├── prelude │ │ └── Primitives.kt │ │ ├── ast │ │ ├── Type.kt │ │ ├── Pattern.kt │ │ ├── Generics.kt │ │ ├── Paths.kt │ │ ├── Token.kt │ │ ├── Stmt.kt │ │ ├── Expr.kt │ │ ├── Lexer.kt │ │ ├── ParserUtils.kt │ │ └── Parser.kt │ │ ├── Zinc.kt │ │ └── CompilerError.kt │ └── main.kt ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── README.md ├── settings.gradle.kts ├── .gitignore ├── gradlew.bat └── gradlew /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style = official 2 | -------------------------------------------------------------------------------- /src/main/kotlin/script.zc: -------------------------------------------------------------------------------- 1 | fn main() { 2 | loop { 3 | fn func() { 4 | break 3; 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/light672/zinc-old/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/GenericArgs.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | internal data class GenericArgs(val types: List) -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/Branch.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | class Branch { 4 | val data = HashMap() 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/TypeParamBounds.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | internal data class TypeParamBounds(val traits: List) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zinc 🪨 2 | a type-safe, embedded programming language. 3 | 4 | currently available for: 5 | - Kotlin (JVM) 6 | - Java 7 | 8 | Documentation coming soon 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/WhereClause.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | internal data class WhereClause(val predicates: List>) -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/prelude/Primitives.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.prelude 2 | 3 | import com.light672.zinc.resolution.TypeItem 4 | 5 | internal object Primitives { 6 | val intItem = TypeItem.Primitive() 7 | val boolItem = TypeItem.Primitive() 8 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | plugins { 9 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" 10 | } 11 | 12 | rootProject.name = "zinc" -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/GenericParams.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.ast.GenericParams as ASTGenericParams 4 | 5 | internal class GenericParams( 6 | val params: List, 7 | val branch: Branch, 8 | val ast: ASTGenericParams 9 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/Type.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | internal sealed interface Type { 4 | data class ADT(val item: TypeItemRef) : Type 5 | data class Tuple(val types: List) : Type 6 | data class Function(val params: List, val returnType: List) : Type 7 | 8 | data object Error : Type 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Type.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | internal sealed interface Type { 4 | data class Tuple(val start: Token, val fields: List, val end: Token) : Type 5 | data class Path(val path: ComplexPath) : Type 6 | data class Error(val range: Token.Range) : Type 7 | 8 | 9 | fun range() = when (this) { 10 | is Error -> range 11 | is Path -> path.range() 12 | is Tuple -> start..end 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/TypeItemRef.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.ast.Token 4 | import com.light672.zinc.dsr.TypeItem 5 | 6 | internal sealed interface TypeItemRef { 7 | data class Normal(val type: TypeItem, val generics: GenericArgs?) : TypeItemRef 8 | data class Qualified( 9 | val type: Type, 10 | val trait: Normal, 11 | val identifier: Token, 12 | val genericArgs: GenericArgs? 13 | ) : TypeItemRef 14 | // add associated trait variant 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/Pattern.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.ast.Pattern as ASTPattern 4 | 5 | internal sealed interface Pattern { 6 | data class Variable(val variable: com.light672.zinc.dsr.Variable, val ast: ASTPattern.Identifier) : Pattern 7 | data class Wildcard(val ast: ASTPattern.Wildcard) : Pattern 8 | data class Literal(val ast: ASTPattern.Literal) : Pattern 9 | data class Tuple(val fields: List, val ast: ASTPattern.Tuple) : Pattern 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/Pattern.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.ast.Token 4 | import com.light672.zinc.ast.Pattern as ASTPattern 5 | 6 | internal sealed interface Pattern { 7 | data class Literal(val token: Token) : Pattern 8 | data class Tuple(val fields: List, val ast: ASTPattern.Tuple) : Pattern 9 | data class Variable(val variable: com.light672.zinc.dsr.Variable, val ast: ASTPattern.Identifier) : Pattern 10 | data class Wildcard(val token: Token) : Pattern 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Pattern.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | internal sealed interface Pattern { 4 | data class Identifier(val token: Token) : Pattern 5 | data class Wildcard(val token: Token) : Pattern 6 | data class Literal(val token: Token) : Pattern 7 | data class Tuple(val start: Token, val fields: List, val end: Token) : Pattern 8 | 9 | fun range() = when (this) { 10 | is Identifier -> token.asRange() 11 | is Literal -> token.asRange() 12 | is Wildcard -> token.asRange() 13 | is Tuple -> start..end 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Generics.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | internal data class GenericArgs(val start: Token, val types: List, val end: Token) 4 | internal data class GenericParams( 5 | val start: Token, 6 | val params: List, 7 | val end: Token 8 | ) 9 | 10 | internal data class GenericParam(val name: Token, val bounds: TypeParamBounds?) 11 | 12 | internal data class TypeParamBounds(val bounds: List) 13 | internal data class WhereClause(val token: Token, val clauseItems: List) 14 | internal data class WhereClauseItem(val type: Type, val bounds: TypeParamBounds) -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/ValueItemRef.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.ast.Token 4 | import com.light672.zinc.dsr.ValueItem 5 | 6 | internal sealed interface ValueItemRef { 7 | data class Normal(val item: ValueItem, val generics: GenericArgs?) : ValueItemRef 8 | data class Qualified( 9 | val type: Type, 10 | val trait: TypeItemRef.Normal, 11 | val identifier: Token, 12 | val genericArgs: GenericArgs? 13 | ) : ValueItemRef 14 | 15 | data class TypeAccess( 16 | val type: Type, 17 | val identifier: Token, 18 | val genericArgs: GenericArgs? 19 | ) : ValueItemRef 20 | 21 | // add enum variant 22 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Paths.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | 4 | internal data class ComplexSegment(val id: Token, val generics: GenericArgs?) { 5 | fun range() = id..(generics?.end ?: id) 6 | } 7 | 8 | internal sealed interface ComplexPath { 9 | data class Normal(val body: List) : ComplexPath 10 | data class Qualified(val start: Token, val type: Type, val trait: Normal?, val end: Token, val body: List) : ComplexPath 11 | data class Error(val range: Token.Range) : ComplexPath 12 | 13 | fun range() = when (this) { 14 | is Error -> range 15 | is Normal -> body.first().id..body.last().let { it.generics?.end ?: it.id } 16 | is Qualified -> start..body.last().let { it.generics?.end ?: it.id } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/Item.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.ast.FunctionParam 4 | import com.light672.zinc.ast.Token 5 | import com.light672.zinc.ast.Pattern as ASTPattern 6 | import com.light672.zinc.ast.Stmt as ASTStmt 7 | 8 | internal sealed interface ValueItem 9 | internal sealed interface TypeItem { 10 | fun name() = when (this) { 11 | is Generic -> "generic" 12 | is Module -> "module" 13 | is Struct -> "struct" 14 | is Trait -> "trait" 15 | is TupleStruct -> "tuple struct" 16 | is UnitStruct -> "unit struct" 17 | } 18 | } 19 | 20 | internal data class Generic(val index: Int, val ast: Token) : TypeItem 21 | internal data class Module(val ast: ASTStmt.Module, val values: Branch, val types: Branch) : TypeItem 22 | internal data class Trait(val ast: ASTStmt.Trait) : TypeItem 23 | internal data class Struct(val ast: ASTStmt.Struct) : TypeItem 24 | internal data class UnitStruct(val ast: ASTStmt.UnitStruct) : TypeItem, ValueItem 25 | internal data class TupleStruct(val ast: ASTStmt.TupleStruct) : TypeItem 26 | internal data class Function(val ast: ASTStmt.Function) : ValueItem 27 | internal data class Variable(val ast: ASTPattern) : ValueItem 28 | internal data class Self(val ast: FunctionParam.Self) : ValueItem 29 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/Stmt.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.ast.FunctionParam as ASTFunctionParam 4 | import com.light672.zinc.ast.Stmt as ASTStmt 5 | 6 | internal sealed interface AssociatedStmt : Stmt 7 | 8 | 9 | internal sealed interface Stmt { 10 | data class Function( 11 | val genericParams: GenericParams?, 12 | val parameterBranch: Branch, 13 | val parameters: List, 14 | val block: Expr.Block?, 15 | val ast: ASTStmt.Function 16 | ) : AssociatedStmt 17 | 18 | data class Trait( 19 | val genericParams: GenericParams?, 20 | val statements: List, 21 | val ast: ASTStmt.Trait 22 | ) : Stmt 23 | 24 | data class Implementation( 25 | val genericParams: GenericParams?, 26 | val statements: List, 27 | val ast: ASTStmt.Implementation 28 | ) : Stmt 29 | 30 | data class UnitStruct( 31 | val genericParams: GenericParams?, 32 | val ast: ASTStmt.UnitStruct 33 | ) : Stmt 34 | 35 | data class TupleStruct( 36 | val genericParams: GenericParams?, 37 | val ast: ASTStmt.TupleStruct 38 | ) : Stmt 39 | 40 | data class Struct( 41 | val genericParams: GenericParams?, 42 | val ast: ASTStmt.Struct 43 | ) : Stmt 44 | 45 | data class Module( 46 | val types: Branch, 47 | val values: Branch, 48 | val statements: List, 49 | val ast: ASTStmt.Module 50 | ) : Stmt 51 | 52 | data class Let( 53 | val branch: Branch, 54 | val pattern: Pattern, 55 | val initializer: Expr?, 56 | val ast: ASTStmt.Let 57 | ) : Stmt 58 | 59 | data class Expression( 60 | val expr: Expr, 61 | val ast: ASTStmt.Expression 62 | ) : Stmt 63 | } 64 | 65 | internal sealed interface FunctionParam { 66 | data class Self(val item: com.light672.zinc.dsr.Self, val ast: ASTFunctionParam.Self) : FunctionParam 67 | data class Pattern(val pattern: com.light672.zinc.dsr.Pattern, val ast: ASTFunctionParam.Pattern) : FunctionParam 68 | } -------------------------------------------------------------------------------- /src/main/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | import com.light672.zinc.Zinc 2 | import java.io.File 3 | import java.nio.charset.Charset 4 | 5 | 6 | fun main() { 7 | val script = File("src/main/kotlin/script.zc").readBytes().toString(Charset.defaultCharset()) 8 | normalTest(script) 9 | 10 | 11 | } 12 | 13 | fun normalTest(source: String) { 14 | val runtime = 15 | Zinc.Runtime( 16 | 256, 17 | 256, 18 | source, 19 | System.out, 20 | System.err, 21 | ) 22 | 23 | runtime.run() 24 | 25 | 26 | } 27 | 28 | /* 29 | 30 | use std::rand; 31 | 32 | enum Type { 33 | Number(int), 34 | Skip, 35 | PlusTwo, 36 | Reverse 37 | } 38 | 39 | impl Type { 40 | fn get_type_from_num(num: int) -> Type { 41 | match num { 42 | 0..9 => Type::Number(num), 43 | 10 => Type::Skip, 44 | 11 => Type::PlusTwo, 45 | 12 => Type::Reverse, 46 | _ => panic("tried to make a card with a number over 12") 47 | } 48 | } 49 | } 50 | 51 | enum WildType { 52 | PlusFour, 53 | Swap, 54 | ChangeColor 55 | } 56 | 57 | enum Card { 58 | Blue(Type), 59 | Red(Type), 60 | Yellow(Type), 61 | Green(Type), 62 | Wild(WildType) 63 | } 64 | 65 | impl Card { 66 | // non-wild 67 | fn get_color_card_from_num(num: int, type: Type) -> Card { 68 | match num { 69 | 0 => Blue(type), 70 | 1 => Red(type), 71 | 2 => Yellow(type), 72 | 3 => Green(type) 73 | } 74 | } 75 | } 76 | 77 | 78 | struct Player { 79 | name: String, 80 | mut cards: List[Card] 81 | } 82 | 83 | struct Game { 84 | mut topCard: Card, 85 | deck: List[Card], 86 | mut deckTop: Int, 87 | 88 | } 89 | 90 | impl Game { 91 | fn new() -> Game { 92 | let numberList = (1..26).map(|x| x % 13); 93 | 94 | let cardList = List::new( 95 | |i| Card::get_color_card_from_num(i / 8, Type::get_type_from_num(i % 13)), 96 | numberList.len() * 4 97 | ); 98 | } 99 | } 100 | 101 | fn main() { 102 | let numberList = 103 | } 104 | */ -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Token.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | internal class Token( 4 | val type: TokenType, 5 | val lexeme: CharSequence?, 6 | val line: Int, 7 | val rangeOnLine: IntRange 8 | ) { 9 | companion object { 10 | fun empty(line: Int = 0, rangeOnLine: IntRange = 0..0) = Token(TokenType.NA, "(EMPTY TOKEN)", line, rangeOnLine) 11 | } 12 | 13 | data class Range(val start: Token, val end: Token) 14 | 15 | operator fun rangeTo(token: Token) = Range(this, token) 16 | fun asRange() = this..this 17 | 18 | override fun toString() = lexeme?.toString() ?: type.asString 19 | } 20 | 21 | internal enum class TokenType( 22 | val asString: String, 23 | ) { 24 | FN("fn"), 25 | AS("as"), 26 | IF("if"), 27 | IN("in"), 28 | FOR("for"), 29 | LET("let"), 30 | MUT("mut"), 31 | MOD("mod"), 32 | ELSE("else"), 33 | LOOP("loop"), 34 | IMPL("impl"), 35 | SELF("self"), 36 | ENUM("enum"), 37 | TRUE("true"), 38 | FALSE("false"), 39 | WHERE("where"), 40 | WHILE("while"), 41 | MATCH("match"), 42 | BREAK("break"), 43 | CONST("const"), 44 | RETURN("return"), 45 | STRUCT("struct"), 46 | CONTINUE("continue"), 47 | INTERFACE("interface"), 48 | TYPEALIAS("typealias"), 49 | UNDERSCORE("_"), 50 | AT("@"), 51 | SEMICOLON(";"), 52 | LEFT_PAREN("("), 53 | RIGHT_PAREN(")"), 54 | LEFT_BRACE("{"), 55 | RIGHT_BRACE("}"), 56 | LEFT_BRACKET("["), 57 | RIGHT_BRACKET("]"), 58 | EQUAL("="), 59 | COLON(":"), 60 | COMMA(","), 61 | DOT("."), 62 | PLUS("+"), 63 | MINUS("-"), 64 | STAR("*"), 65 | SLASH("/"), 66 | PERCENT("%"), 67 | LESS("<"), 68 | GREATER(">"), 69 | AMP("&"), 70 | PIPE("|"), 71 | CARET("^"), 72 | BANG("!"), 73 | TILDA("~"), 74 | EQUAL_EQUAL("=="), 75 | LESS_EQUAL("<="), 76 | GREATER_EQUAL(">="), 77 | AMP_AMP("&&"), 78 | PIPE_PIPE("||"), 79 | PLUS_EQUAL("+="), 80 | MINUS_EQUAL("-="), 81 | STAR_EQUAL("*="), 82 | SLASH_EQUAL("/="), 83 | PERCENT_EQUAL("%="), 84 | CARET_EQUAL("^="), 85 | PIPE_EQUAL("|="), 86 | AMP_EQUAL("&="), 87 | PLUS_PLUS("++"), 88 | MINUS_MINUS("--"), 89 | BANG_EQUAL("!="), 90 | COLON_COLON("::"), 91 | DOT_DOT(".."), 92 | MINUS_ARROW("->"), 93 | EQUALS_ARROW("=>"), 94 | IDENTIFIER("IDENTIFIER"), 95 | NUMBER("NUMBER"), 96 | STRING("STRING"), 97 | NA("NA"), 98 | ERROR("ERROR"), 99 | EOF("EOF"); 100 | 101 | override fun toString() = asString 102 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/Stmt.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.ast.Token 4 | import com.light672.zinc.dsr.GenericParams 5 | import com.light672.zinc.ast.FunctionParam as ASTFunctionParam 6 | import com.light672.zinc.ast.Stmt as ASTStmt 7 | import com.light672.zinc.dsr.FunctionParam as DSRFunctionParam 8 | 9 | internal sealed interface AssociatedStmt : Stmt 10 | 11 | internal sealed interface Stmt { 12 | data class Function( 13 | val generics: GenericParams?, 14 | val whereClause: WhereClause, 15 | val parameters: List, 16 | val block: Expr.Block?, 17 | val ast: ASTStmt.Function 18 | ) : AssociatedStmt 19 | 20 | data class InherentImpl( 21 | val generics: GenericParams?, 22 | val whereClause: WhereClause, 23 | val type: Type, 24 | val statements: List, 25 | val ast: ASTStmt.Implementation 26 | ) : Stmt 27 | 28 | data class TraitImpl( 29 | val generics: GenericParams?, 30 | val whereClause: WhereClause, 31 | val type: Type, 32 | val trait: TypeItemRef.Normal?, 33 | val statements: List, 34 | val ast: ASTStmt.Implementation 35 | ) : Stmt 36 | 37 | data class Trait( 38 | val generics: GenericParams?, 39 | val whereClause: WhereClause, 40 | val statements: List, 41 | val ast: ASTStmt.Trait 42 | ) : Stmt 43 | 44 | data class Expression( 45 | val expr: Expr, 46 | val ast: ASTStmt.Expression 47 | ) : Stmt 48 | 49 | data class Let( 50 | val pattern: Pattern, 51 | val type: Type?, 52 | val initializer: Expr?, 53 | val ast: ASTStmt.Let 54 | ) : Stmt 55 | 56 | data class Module( 57 | val statements: List 58 | ) : Stmt 59 | 60 | data class Struct( 61 | val generics: GenericParams?, 62 | val whereClause: WhereClause, 63 | val fields: List>, 64 | val ast: ASTStmt.Struct 65 | ) : Stmt 66 | 67 | data class TupleStruct( 68 | val generics: GenericParams?, 69 | val whereClause: WhereClause, 70 | val fields: List, 71 | val ast: ASTStmt.TupleStruct 72 | ) : Stmt 73 | 74 | data class UnitStruct( 75 | val generics: GenericParams?, 76 | val whereClause: WhereClause, 77 | val ast: ASTStmt.UnitStruct 78 | ) : Stmt 79 | } 80 | 81 | internal sealed interface FunctionParam { 82 | data class Self(val dsr: DSRFunctionParam, val type: Type?) : FunctionParam 83 | data class Pattern(val pattern: com.light672.zinc.hir.Pattern, val type: Type, val ast: ASTFunctionParam) : FunctionParam 84 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/Zinc.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc 2 | 3 | import com.light672.zinc.ast.Parser 4 | import com.light672.zinc.ast.TokenType 5 | import com.light672.zinc.resolution.Resolver 6 | import com.light672.zinc.resolution.Scope 7 | import java.io.PrintStream 8 | 9 | object Zinc { 10 | internal const val INDENT_SIZE = 4 11 | 12 | class Runtime internal constructor( 13 | private val stackSize: Int, 14 | private val callStackSize: Int, 15 | internal val source: String, 16 | internal val out: PrintStream, 17 | private val err: PrintStream, 18 | ) { 19 | private var hadError = false 20 | private lateinit var lines: List 21 | 22 | 23 | fun run() { 24 | val parser = Parser(this) 25 | val stmtsResult = with(parser) { with(combinator) { expect(manyUntil(::declaration, TokenType.EOF)) } } 26 | if (!stmtsResult.isSuccess()) return 27 | val (stmts, eof) = +stmtsResult 28 | val scope = Scope() 29 | val resolver = Resolver(this) 30 | stmts.forEach { resolver.defineScope(it, scope) } 31 | val irStmts = stmts.map { resolver.stmt(it, scope) } 32 | println(stmts) 33 | } 34 | 35 | internal fun reportCompileError(error: CompilerError) { 36 | val (start, end) = error.range 37 | if (!this::lines.isInitialized) 38 | lines = source.replace("\t", "".padEnd(INDENT_SIZE)).split("\n") 39 | err.println("line ${start.line}: ${error.message}") 40 | val padLength = end.toString().length 41 | err.println(" | ".padStart(padLength + 3)) 42 | 43 | val lines = start.line..end.line 44 | val range = start.rangeOnLine.first.coerceAtLeast(end.rangeOnLine.first)..start.rangeOnLine.last.coerceAtLeast(end.rangeOnLine.last) 45 | 46 | for (line in lines) { 47 | err.println("${line.toString().padStart(padLength)} | ${this.lines[line - 1]}") 48 | } 49 | err.println( 50 | " | " 51 | .padStart(padLength + 3) 52 | .padEnd(padLength + 3 + range.first) + "" 53 | .padEnd( 54 | range.last - range.first, 55 | '^' 56 | ) 57 | .let { 58 | if (error.secondaryLabel.isNotEmpty()) "$it - ${error.secondaryLabel}" 59 | else it 60 | } 61 | ) 62 | if (error.primaryLabel.isEmpty()) { 63 | err.println() 64 | return 65 | } 66 | 67 | err.println(" | ".padStart(padLength + 3) + "|".padStart(range.first + 1)) 68 | err.println(" | ".padStart(padLength + 3) + "".padStart(range.first) + error.primaryLabel) 69 | } 70 | } 71 | 72 | 73 | internal inline fun time(block: () -> Unit): Long { 74 | val time = System.currentTimeMillis() 75 | block() 76 | return System.currentTimeMillis() - time 77 | } 78 | 79 | 80 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/Expr.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.ast.Expr as ASTExpr 4 | 5 | 6 | internal sealed interface JumpableExpr : Expr 7 | internal sealed interface Expr { 8 | data class Literal( 9 | val ast: ASTExpr.Literal 10 | ) : Expr 11 | 12 | data class Path( 13 | val ast: ASTExpr.Path 14 | ) : Expr 15 | 16 | data class Group( 17 | val exprs: List, 18 | val ast: ASTExpr.Group 19 | ) : Expr 20 | 21 | data class FieldGet( 22 | val callee: Expr, 23 | val ast: ASTExpr.FieldGet 24 | ) : Expr 25 | 26 | data class Call( 27 | val callee: Expr, 28 | val args: List, 29 | val ast: ASTExpr.Call 30 | ) : Expr 31 | 32 | data class Index( 33 | val callee: Expr, 34 | val args: List, 35 | val ast: ASTExpr.Index 36 | ) : Expr 37 | 38 | data class Unary( 39 | val right: Expr, 40 | val ast: ASTExpr.Unary 41 | ) : Expr 42 | 43 | data class Range( 44 | val left: Expr?, 45 | val right: Expr?, 46 | val ast: ASTExpr.Range 47 | ) : Expr 48 | 49 | data class Binary( 50 | val left: Expr, 51 | val right: Expr, 52 | val ast: ASTExpr.Binary 53 | ) : Expr 54 | 55 | data class Closure( 56 | val paramScope: Branch, 57 | val patterns: List, 58 | val expr: Expr, 59 | val ast: ASTExpr.Closure 60 | ) : Expr 61 | 62 | data class Return( 63 | val value: Expr?, 64 | val ast: ASTExpr.Return 65 | ) : Expr 66 | 67 | data class Break( 68 | val value: Expr?, 69 | val ast: ASTExpr.Break 70 | ) : Expr 71 | 72 | data class Continue( 73 | val ast: ASTExpr.Continue 74 | ) : Expr 75 | 76 | data class Block( 77 | val types: Branch, 78 | val values: Branch, 79 | val stmts: List, 80 | val ast: ASTExpr.Block 81 | ) : JumpableExpr 82 | 83 | data class If( 84 | val condition: Expr, 85 | val then: Block, 86 | val orElse: Expr?, 87 | val ast: ASTExpr.If 88 | ) : JumpableExpr 89 | 90 | data class While( 91 | val condition: Expr, 92 | val then: Block, 93 | val ast: ASTExpr.While 94 | ) : JumpableExpr 95 | 96 | data class For( 97 | val patternScope: Branch, 98 | val pattern: Pattern, 99 | val iterator: Expr, 100 | val block: Block, 101 | val ast: ASTExpr.For 102 | ) : JumpableExpr 103 | 104 | data class Match( 105 | val expr: Expr, 106 | val branches: List, Pattern, Expr>>, 107 | val ast: ASTExpr.Match 108 | ) : Expr 109 | 110 | data class Loop( 111 | val block: Block, 112 | val ast: ASTExpr.Loop 113 | ) : JumpableExpr 114 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/Expr.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.ast.Token 4 | import com.light672.zinc.ast.Expr as ASTExpr 5 | 6 | 7 | internal sealed interface Expr { 8 | data class Literal( 9 | val ast: ASTExpr.Literal 10 | ) : Expr 11 | 12 | data class Item( 13 | val variable: ValueItemRef?, 14 | val ast: ASTExpr.Path 15 | ) : Expr 16 | 17 | data class Tuple( 18 | val exprs: List, 19 | val ast: ASTExpr.Group 20 | ) : Expr 21 | 22 | data class FieldGet( 23 | val callee: Expr, 24 | val identifier: Token, 25 | val genericArgs: GenericArgs?, 26 | val ast: ASTExpr.FieldGet 27 | ) : Expr 28 | 29 | data class MethodCall( 30 | val callee: Expr, 31 | val identifier: Token, 32 | val genericArgs: GenericArgs?, 33 | val args: List, 34 | val ast: ASTExpr.Call 35 | ) : Expr 36 | 37 | 38 | data class Call( 39 | val callee: Expr, 40 | val args: List, 41 | val ast: ASTExpr.Call 42 | ) : Expr 43 | 44 | data class Index( 45 | val callee: Expr, 46 | val args: List, 47 | val ast: ASTExpr.Index 48 | ) : Expr 49 | 50 | data class Unary( 51 | val right: Expr, 52 | val ast: ASTExpr.Unary 53 | ) : Expr 54 | 55 | data class Range( 56 | val left: Expr?, 57 | val right: Expr?, 58 | val ast: ASTExpr.Range 59 | ) : Expr 60 | 61 | data class Binary( 62 | val left: Expr, 63 | val right: Expr, 64 | val ast: ASTExpr.Binary 65 | ) : Expr 66 | 67 | data class Closure( 68 | val patterns: List, 69 | val expr: Expr, 70 | val ast: ASTExpr.Closure 71 | ) : Expr 72 | 73 | // TODO: add function to return from 74 | data class Return( 75 | val value: Expr?, 76 | val ast: ASTExpr.Return 77 | ) : Expr 78 | 79 | // TODO: add labels to break and continue 80 | data class Break( 81 | val value: Expr?, 82 | val ast: ASTExpr.Break 83 | ) : Expr 84 | 85 | data class Continue( 86 | val ast: ASTExpr.Continue 87 | ) : Expr 88 | 89 | data class Block( 90 | val stmts: List, 91 | val ast: ASTExpr.Block 92 | ) : Expr 93 | 94 | data class If( 95 | val condition: Expr, 96 | val then: Block, 97 | val orElse: Expr?, 98 | val ast: ASTExpr.If 99 | ) : Expr 100 | 101 | data class Match( 102 | val expr: Expr, 103 | val branches: List>, 104 | val ast: ASTExpr.Match 105 | ) : Expr 106 | 107 | data class Loop( 108 | val block: Block, 109 | val ast: ASTExpr.Loop 110 | ) : Expr 111 | 112 | data class While( 113 | val condition: Expr, 114 | val block: Block, 115 | val ast: ASTExpr.While 116 | ) : Expr 117 | 118 | data class For( 119 | val pattern: Pattern, 120 | val iterator: Expr, 121 | val block: Block, 122 | val ast: ASTExpr.For 123 | ) : Expr 124 | 125 | 126 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Stmt.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | import com.light672.zinc.resolution.Scope 4 | import com.light672.zinc.resolution.TypeItem 5 | 6 | internal sealed interface Stmt { 7 | data class Function( 8 | val keyword: Token, 9 | val name: Token, 10 | val genericParams: GenericParams?, 11 | val params: List, 12 | val paramClose: Token, 13 | val returnType: Type?, 14 | val whereClause: WhereClause?, 15 | val block: Expr.Block? 16 | ) : AssociatedStmt 17 | 18 | data class Trait( 19 | val keyword: Token, 20 | val name: Token, 21 | val genericParams: GenericParams?, 22 | val whereClause: WhereClause?, 23 | val statements: List 24 | ) : Stmt 25 | 26 | data class Implementation( 27 | val keyword: Token, 28 | val genericParams: GenericParams?, 29 | val type: Type, 30 | val trait: ComplexPath.Normal?, 31 | val whereClause: WhereClause?, 32 | val statements: List 33 | ) : Stmt 34 | 35 | data class UnitStruct( 36 | val keyword: Token, 37 | val name: Token, 38 | val genericParams: GenericParams?, 39 | val whereClause: WhereClause?, 40 | val semicolon: Token 41 | ) : Stmt { 42 | lateinit var item: TypeItem.UnitStruct 43 | lateinit var genericScope: Scope 44 | } 45 | 46 | data class TupleStruct( 47 | val keyword: Token, 48 | val name: Token, 49 | val genericParams: GenericParams?, 50 | val fields: List, 51 | val whereClause: WhereClause?, 52 | val close: Token 53 | ) : Stmt 54 | 55 | data class Struct( 56 | val keyword: Token, 57 | val name: Token, 58 | val genericParams: GenericParams?, 59 | val fields: List>, 60 | val whereClause: WhereClause?, 61 | val close: Token 62 | ) : Stmt 63 | 64 | data class Module( 65 | val keyword: Token, 66 | val name: Token, 67 | val statements: List, 68 | val close: Token 69 | ) : Stmt 70 | 71 | data class Let( 72 | val keyword: Token, 73 | val pattern: Pattern, 74 | val type: Type?, 75 | val initializer: Expr?, 76 | ) : Stmt 77 | 78 | data class Expression(val expr: Expr, val semicolon: Token?) : Stmt 79 | 80 | // TODO: include where clauses in range 81 | fun range() = when (this) { 82 | is Expression -> expr.range().let { it.start..(semicolon?.asRange()?.end ?: it.end) } 83 | is Function -> keyword..(returnType?.range()?.end ?: paramClose) 84 | is Let -> keyword..(initializer?.range()?.end ?: type?.range()?.end ?: pattern.range().end) 85 | is Module -> keyword..name 86 | is Struct -> keyword..(genericParams?.end ?: name) 87 | is TupleStruct -> keyword..(genericParams?.end ?: name) 88 | is UnitStruct -> keyword..(genericParams?.end ?: name) 89 | is Implementation -> keyword..(trait?.range()?.end ?: type.range().end) 90 | is Trait -> keyword..(genericParams?.end ?: name) 91 | } 92 | } 93 | 94 | internal sealed interface FunctionParam { 95 | data class Self(val self: Token, val type: Type?) : FunctionParam 96 | data class Pattern(val pattern: com.light672.zinc.ast.Pattern, val type: Type) : FunctionParam 97 | } 98 | 99 | internal sealed interface AssociatedStmt : Stmt -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Expr.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | internal sealed interface Expr { 4 | data class Literal(val token: Token) : Expr 5 | data class Path(val path: ComplexPath) : Expr 6 | data class Group(val open: Token, val expressions: List, val close: Token) : Expr 7 | data class FieldGet(val callee: Expr, val segment: ComplexSegment) : Expr 8 | data class Call(val callee: Expr, val argOpen: Token, val args: List, val argClose: Token) : Expr 9 | data class Index(val callee: Expr, val argOpen: Token, val args: List, val argClose: Token) : Expr 10 | data class Unary(val operator: Token, val right: Expr) : Expr 11 | data class Range(val left: Expr?, val operator: Token, val right: Expr?) : Expr 12 | data class Binary(val left: Expr, val operator: Token, val right: Expr) : Expr 13 | data class Closure(val open: Token, val params: List>, val close: Token, val type: Type?, val expr: Expr) : Expr 14 | data class Return(val keyword: Token, val expr: Expr?) : Expr 15 | data class Break(val keyword: Token, val label: Token?, val expr: Expr?) : Expr 16 | data class Continue(val keyword: Token, val label: Token?) : Expr 17 | data class Block(val label: Token?, val start: Token, val stmts: List, val end: Token) : Expr 18 | 19 | data class If(val label: Token?, val keyword: Token, val condition: Expr, val thenBlock: Block, val elseExpr: Expr?) : Expr 20 | data class While(val label: Token?, val keyword: Token, val condition: Expr, val block: Block) : Expr 21 | data class For(val label: Token?, val keyword: Token, val pattern: Pattern, val iterator: Expr, val block: Block) : Expr 22 | data class Match(val keyword: Token, val expr: Expr, val branches: List>, val close: Token) : Expr 23 | data class Loop(val label: Token?, val keyword: Token, val block: Block) : Expr 24 | 25 | 26 | fun range(): Token.Range { 27 | return when (this) { 28 | is Binary -> left.range().start..right.range().end 29 | is Break -> keyword..(expr?.range()?.end ?: keyword) 30 | is Call -> callee.range().start..argClose 31 | is Closure -> open..expr.range().end 32 | is Group -> open..close 33 | is Index -> callee.range().start..argClose 34 | is Literal -> token.asRange() 35 | is Path -> when (path) { 36 | is ComplexPath.Normal -> path.body.first().id..path.body.last().let { last -> last.generics?.end ?: last.id } 37 | is ComplexPath.Qualified -> path.start..path.body.last().let { last -> last.generics?.end ?: last.id } 38 | is ComplexPath.Error -> path.range 39 | } 40 | 41 | is Range -> (left?.range()?.start ?: operator)..(right?.range()?.end ?: operator) 42 | is Return -> keyword..(expr?.range()?.end ?: keyword) 43 | is Unary -> operator..right.range().end 44 | 45 | is Block -> start..end 46 | is If -> keyword..(elseExpr?.range()?.end ?: thenBlock.end) 47 | is While -> keyword..block.end 48 | is Loop -> keyword..block.end 49 | is For -> keyword..block.end 50 | is Match -> keyword..close 51 | is FieldGet -> callee.range().start..(segment.generics?.end ?: segment.id) 52 | is Continue -> keyword..(label ?: keyword) 53 | } 54 | } 55 | 56 | fun name() = when (this) { 57 | is Binary -> "binary expression" 58 | is Break -> "break expression" 59 | is Call -> "call expression" 60 | is Closure -> "closure" 61 | is Group -> "group expression" 62 | is Index -> "indexing expression" 63 | is Literal -> "literal expression" 64 | is Path -> "path expression" 65 | is Range -> "range expression" 66 | is Return -> "return expression" 67 | is Unary -> "unary expression" 68 | is Block -> "block expression" 69 | is If -> "if expression" 70 | is While -> "while expression" 71 | is Loop -> "loop expression" 72 | is For -> "for expression" 73 | is Match -> "match expression" 74 | is FieldGet -> "field access" 75 | is Continue -> "continue expression" 76 | } 77 | 78 | 79 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/CompilerError.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc 2 | 3 | import com.light672.zinc.ast.Expr 4 | import com.light672.zinc.ast.Token 5 | import com.light672.zinc.ast.TokenType 6 | 7 | internal class CompilerError( 8 | val message: String, 9 | val range: Token.Range, 10 | val primaryLabel: String = "", 11 | val secondaryLabel: String = "" 12 | ) { 13 | companion object { 14 | val EMPTY = CompilerError("", Token.empty().asRange()) 15 | 16 | // lexer 17 | fun unexpectedChar(char: Char, line: Int, currentOnLine: Int) = 18 | CompilerError("unexpected char `$char`", Token.empty(line, currentOnLine..currentOnLine).asRange(), "unexpected char") 19 | 20 | fun unterminatedString(char: Char, line: Int, currentOnLine: Int) = 21 | CompilerError("unterminated string", Token.empty(line, currentOnLine..currentOnLine).asRange(), "expected `\"`") 22 | 23 | // parser 24 | 25 | fun unexpectedToken(token: Token, expected: TokenType) = 26 | CompilerError("unexpected token `$token`, expected `$expected`", token.asRange(), "expected `$expected`") 27 | 28 | fun unexpectedToken(token: Token, expected: Array) = 29 | CompilerError("unexpected token `$token`, expected one of ${expected.asList().map { "`$it`" }.joinToString(" ")}", token.asRange()) 30 | 31 | fun expectedPathSegment(expr: Expr) = 32 | CompilerError("expected path segment in path but got ${expr.name()}", expr.range(), "expected path segment") 33 | 34 | fun expectedType(expr: Expr) = 35 | CompilerError("expected type but got ${expr.name()}", expr.range(), "expected type") 36 | 37 | fun expectedType(token: Token) = 38 | CompilerError("expected type but got $token", token.asRange(), "expected type") 39 | 40 | fun expectedExpression(token: Token) = 41 | CompilerError("expected expression but got `$token`", token.asRange(), "expected expression") 42 | 43 | fun expectedBlockExpr(token: Token) = 44 | unexpectedToken(token, arrayOf(TokenType.IF, TokenType.WHILE, TokenType.FOR, TokenType.LOOP, TokenType.LEFT_BRACE)) 45 | 46 | fun expectedStatement(token: Token) = 47 | CompilerError("expected statement but got `$token`", token.asRange(), "expected statement") 48 | 49 | fun expectedAssociatedStatement(token: Token) = 50 | CompilerError( 51 | "expected function but got `$token`", // TODO: add typealias and const to this once implemented 52 | token.asRange(), 53 | "expected associated statement" 54 | ) 55 | 56 | fun expectedPattern(token: Token) = 57 | CompilerError("expected pattern but got `$token`", token.asRange(), "expected pattern") 58 | 59 | fun expectedPathSegment(token: Token) = 60 | CompilerError("expected a path segment leading with `::` after qualified segment", token.asRange(), "expected `::`") 61 | 62 | 63 | // ast contextualizer 64 | fun usedGenericParamNameInItem(token: Token) = 65 | CompilerError( 66 | "the name `$token` is already used as a generic parameter in the current item", 67 | token.asRange(), 68 | "`$token` declared again here" 69 | ) 70 | 71 | fun nameAlreadyExists(name: CharSequence, declRange: Token.Range, inEnvironment: String) = 72 | CompilerError("item `$name` already exists in $inEnvironment", declRange, "previously declared") 73 | 74 | 75 | // resolver 76 | fun fieldAlreadyExists(field: Token) = 77 | CompilerError("field `$field` already exists in struct", field.asRange(), "field name `$field` used more than once") 78 | 79 | fun cannotShadowName(name: CharSequence, declRange: Token.Range) = 80 | CompilerError("item `$name` cannot be shadowed in scope", declRange, "previously declared") 81 | 82 | fun nameNotFound(name: CharSequence, range: Token.Range, inEnvironment: String) = 83 | CompilerError("item `$name` does not exist in $inEnvironment", range, "not found in $inEnvironment") 84 | 85 | fun labelNotFound(name: CharSequence, range: Token.Range) = 86 | CompilerError("label `$name` does not exist in scope", range, "not found in scope") 87 | 88 | fun loopNotFound(expr: Expr) = 89 | CompilerError("could not find loop for ${expr.name()}", expr.range(), "no loop found, consider using a label") 90 | 91 | fun genericsNotAllowedIn(range: Token.Range, item: String) = 92 | CompilerError("generic arguments should not be provided for $item", range, "remove generic arguments") 93 | 94 | fun useQualifiedPath(name: Token, range: Token.Range) = 95 | CompilerError("a qualified path must be used to verify the use of `$name`", range, "use qualified path") 96 | 97 | fun patternMustBeIrrefutable(pattern: Token.Range) = 98 | CompilerError("pattern must be able to match any value", pattern, "pattern is refutable") 99 | 100 | fun cannotCaptureDynamicEnvironment(token: Token) = 101 | CompilerError("cannot capture dynamic environment outside of item", token.asRange(), "`$token` is declared outside of item") 102 | 103 | 104 | fun cannotUseLabelsOutsideItem(token: Token) = 105 | CompilerError( 106 | "cannot use label `$token` as it is defined outside the current function", 107 | token.asRange(), 108 | "`$token` is declared outside of item" 109 | ) 110 | 111 | fun itemDoesNotHaveAssociatedItems(name: Token, item: String) = 112 | CompilerError("item $item does not contain associated items", name.asRange(), "cannot access in $item") 113 | 114 | fun expectedTrait(range: Token.Range, got: String) = 115 | CompilerError("expected a trait but got `$got`", range, "expected a trait") 116 | 117 | } 118 | } 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Lexer.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | import com.light672.zinc.CompilerError 4 | import com.light672.zinc.Zinc 5 | import com.light672.zinc.ast.TokenType.* 6 | 7 | internal class Lexer(private val source: String, private val zinc: Zinc.Runtime) { 8 | 9 | private var start = 0 10 | private var current = 0 11 | private var startOnLine = 0 12 | private var currentOnLine = 0 13 | private var line = 1 14 | private val char get() = if (atEnd()) '\u0000' else source[current] 15 | private val previous get() = if (atBeginning()) '\u0000' else source[current - 1] 16 | private val next get() = if (current + 1 >= source.length) '\u0000' else source[current + 1] 17 | 18 | fun scanTokens(): List { 19 | val tokens = ArrayList() 20 | do { 21 | val t = scanToken() 22 | tokens.add(t) 23 | } while (t.type != EOF) 24 | return tokens 25 | } 26 | 27 | fun scanToken(): Token { 28 | skipWhiteSpace() 29 | if (atEnd()) return Token(EOF, "EOF", line, startOnLine..currentOnLine) 30 | return when (consume()) { 31 | in '0'..'9' -> number() 32 | in 'a'..'z', in 'A'..'Z', '_' -> keyword() 33 | 34 | '"' -> string() 35 | '#' -> { 36 | while (char != '\n' && !atEnd()) consume() 37 | scanToken() 38 | } 39 | 40 | '@' -> create(AT) 41 | ';' -> create(SEMICOLON) 42 | '(' -> create(LEFT_PAREN) 43 | ')' -> create(RIGHT_PAREN) 44 | '{' -> create(LEFT_BRACE) 45 | '}' -> create(RIGHT_BRACE) 46 | '[' -> create(LEFT_BRACKET) 47 | ']' -> create(RIGHT_BRACKET) 48 | ',' -> create(COMMA) 49 | '~' -> create(TILDA) 50 | ':' -> create(normalOrDouble(COLON, COLON_COLON)) 51 | '.' -> create(normalOrDouble(DOT, DOT_DOT)) 52 | '=' -> create(if (match('>')) EQUALS_ARROW else normalOrEqual(EQUAL, EQUAL_EQUAL)) 53 | '^' -> create(normalOrEqual(CARET, CARET_EQUAL)) 54 | '!' -> create(normalOrEqual(BANG, BANG_EQUAL)) 55 | '*' -> create(normalOrEqual(STAR, STAR_EQUAL)) 56 | '/' -> create(normalOrEqual(SLASH, SLASH_EQUAL)) 57 | '%' -> create(normalOrEqual(PERCENT, PERCENT_EQUAL)) 58 | '<' -> create(normalOrEqual(LESS, LESS_EQUAL)) 59 | '>' -> create(normalOrEqual(GREATER, GREATER_EQUAL)) 60 | '+' -> create(normalDoubleOrEqual(PLUS, PLUS_PLUS, PLUS_EQUAL)) 61 | '-' -> create(if (match('>')) MINUS_ARROW else normalDoubleOrEqual(MINUS, MINUS_MINUS, MINUS_EQUAL)) 62 | '&' -> create(normalDoubleOrEqual(AMP, AMP_AMP, AMP_EQUAL)) 63 | '|' -> create(normalDoubleOrEqual(PIPE, PIPE_PIPE, PIPE_EQUAL)) 64 | 65 | else -> error(CompilerError.unexpectedChar(char, currentOnLine, line)) 66 | } 67 | } 68 | 69 | private fun normalOrDouble(normal: TokenType, double: TokenType) = if (match(previous)) double else normal 70 | private fun normalOrEqual(normal: TokenType, equal: TokenType) = if (match('=')) equal else normal 71 | private fun normalDoubleOrEqual(normal: TokenType, double: TokenType, equal: TokenType) = 72 | if (match(previous)) double else normalOrEqual(normal, equal) 73 | 74 | private fun number(): Token { 75 | while (isNumeric(char)) consume() 76 | if (char == '.' && isNumeric(next)) { 77 | consume() 78 | while (isNumeric(char)) consume() 79 | } 80 | return createWithLexeme(NUMBER) 81 | } 82 | 83 | private fun string(): Token { 84 | start = current 85 | startOnLine = currentOnLine 86 | while (char != '"' && !atEnd()) { 87 | if (char == '\n') { 88 | line++ 89 | return error(CompilerError.unterminatedString(char, currentOnLine, line)) 90 | } 91 | consume() 92 | } 93 | if (atEnd()) error(CompilerError.unterminatedString(char, currentOnLine, line)) 94 | val string = createWithLexeme(STRING) 95 | consume() 96 | return string 97 | } 98 | 99 | private fun keyword(): Token { 100 | while (isAlphaNumeric(char)) consume() 101 | val lexeme = source.subSequence(start, current) 102 | val type = when (lexeme) { 103 | "_" -> UNDERSCORE 104 | "fn" -> FN 105 | "as" -> AS 106 | "in" -> IN 107 | "if" -> IF 108 | "for" -> FOR 109 | "let" -> LET 110 | "mut" -> MUT 111 | "mod" -> MOD 112 | "else" -> ELSE 113 | "loop" -> LOOP 114 | "impl" -> IMPL 115 | "self" -> SELF 116 | "enum" -> ENUM 117 | "true" -> TRUE 118 | "false" -> FALSE 119 | "where" -> WHERE 120 | "while" -> WHILE 121 | "match" -> MATCH 122 | "break" -> BREAK 123 | "const" -> CONST 124 | "return" -> RETURN 125 | "struct" -> STRUCT 126 | "continue" -> CONTINUE 127 | "interface" -> INTERFACE 128 | "typealias" -> TYPEALIAS 129 | else -> IDENTIFIER 130 | } 131 | return if (type == IDENTIFIER) createWithLexeme(type) 132 | else create(type) 133 | } 134 | 135 | 136 | private fun skipWhiteSpace() { 137 | while (!atEnd()) { 138 | when (char) { 139 | ' ', 140 | '\r' -> consume() 141 | 142 | '\t' -> { 143 | consume() 144 | currentOnLine += Zinc.INDENT_SIZE - 1 145 | } 146 | 147 | '\n' -> { 148 | line++ 149 | consume() 150 | startOnLine = 0 151 | currentOnLine = 0 152 | } 153 | 154 | else -> break 155 | } 156 | } 157 | 158 | start = current 159 | startOnLine = currentOnLine 160 | } 161 | 162 | private fun create(type: TokenType): Token { 163 | start = current 164 | val previousRange = startOnLine..currentOnLine 165 | startOnLine = currentOnLine 166 | return Token(type, null, line, previousRange) 167 | } 168 | 169 | private fun createWithLexeme(type: TokenType): Token { 170 | val lexeme = source.subSequence(start, current) 171 | start = current 172 | val previousRange = startOnLine..currentOnLine 173 | startOnLine = currentOnLine 174 | return Token(type, lexeme, line, previousRange) 175 | } 176 | 177 | private fun error(error: CompilerError): Token { 178 | val lexeme = source.subSequence(start, current) 179 | start = current 180 | val previousRange = startOnLine..currentOnLine 181 | startOnLine = currentOnLine 182 | zinc.reportCompileError(error) 183 | return Token(ERROR, lexeme, line, previousRange) 184 | } 185 | 186 | private fun atEnd() = current >= source.length 187 | private fun atBeginning() = current <= 0 188 | private fun consume(): Char { 189 | currentOnLine++ 190 | return source[current++] 191 | } 192 | 193 | private fun match(expected: Char): Boolean { 194 | if (atEnd() || source[current] != expected) return false 195 | consume() 196 | return true 197 | } 198 | 199 | private fun isAlpha(char: Char) = char in 'a'..'z' || char in 'A'..'Z' || char == '_' 200 | private fun isNumeric(char: Char) = char in '0'..'9' 201 | private fun isAlphaNumeric(char: Char) = isNumeric(char) || isAlpha(char) 202 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/ParserUtils.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | import com.light672.zinc.CompilerError 4 | import com.light672.zinc.Zinc 5 | import com.light672.zinc.ast.TokenType.EOF 6 | 7 | 8 | internal sealed interface ParseResult { 9 | data class Success(val value: T) : ParseResult 10 | data object Error : ParseResult 11 | data class NoMatch(val error: CompilerError) : ParseResult 12 | 13 | operator fun unaryPlus() = unwrap() 14 | fun unwrap() = when (this) { 15 | is Success -> value 16 | else -> throw IllegalArgumentException() 17 | } 18 | 19 | fun isSuccess() = this is Success 20 | } 21 | 22 | internal class CombinatorParser(private val zinc: Zinc.Runtime) { 23 | private val lexer = Lexer(zinc.source, zinc) 24 | var previous = Token.empty() 25 | var current = lexer.scanToken() 26 | 27 | fun success(value: T) = ParseResult.Success(value) 28 | fun failure() = ParseResult.Error 29 | fun noMatch(error: CompilerError) = ParseResult.NoMatch(error) 30 | 31 | fun optional(result: ParseResult): ParseResult { 32 | return when (result) { 33 | is ParseResult.Error -> result 34 | is ParseResult.NoMatch -> ParseResult.Success(null) 35 | is ParseResult.Success -> result 36 | } 37 | } 38 | 39 | inline infix fun ParseResult.or(parser: () -> ParseResult): ParseResult { 40 | return when (this) { 41 | ParseResult.Error -> this 42 | is ParseResult.NoMatch -> parser() 43 | is ParseResult.Success -> this 44 | } 45 | } 46 | 47 | fun expect(result: ParseResult): ParseResult { 48 | return when (result) { 49 | ParseResult.Error, is ParseResult.Success -> result 50 | is ParseResult.NoMatch -> { 51 | zinc.reportCompileError(result.error) 52 | ParseResult.Error 53 | } 54 | } 55 | } 56 | 57 | fun token(type: TokenType): ParseResult { 58 | return if (consumeIfMatch(type)) ParseResult.Success(previous) 59 | else ParseResult.NoMatch(CompilerError.unexpectedToken(current, type)) 60 | } 61 | 62 | fun token(vararg types: TokenType): ParseResult { 63 | return if (consumeIfMatch(types)) ParseResult.Success(previous) 64 | else ParseResult.NoMatch(CompilerError.unexpectedToken(current, types)) 65 | } 66 | 67 | 68 | inline fun ParseResult.map(transform: (T) -> R) = map(this, transform) 69 | 70 | @JvmName("mapFunc") 71 | inline fun map(result: ParseResult, transform: (T) -> R): ParseResult { 72 | return when (result) { 73 | is ParseResult.Error -> result 74 | is ParseResult.NoMatch -> result 75 | is ParseResult.Success -> ParseResult.Success(transform(result.value)) 76 | } 77 | } 78 | 79 | inline fun ParseResult.flatMap(transform: (T) -> ParseResult): ParseResult { 80 | return when (val result = this) { 81 | is ParseResult.Error -> result 82 | is ParseResult.NoMatch -> result 83 | is ParseResult.Success -> transform(result.value) 84 | } 85 | } 86 | 87 | inline fun ParseResult.then(parser: () -> ParseResult): ParseResult = flatMap { _ -> parser() } 88 | 89 | inline fun ParseResult.with(action: (T) -> Unit): ParseResult = with(this, action) 90 | 91 | @JvmName("withFunc") 92 | inline fun with(result: ParseResult, action: (T) -> Unit) = map(result) { r -> action(r); r } 93 | 94 | inline fun many(parser: () -> ParseResult, existing: List? = null): ParseResult> { 95 | val list = existing?.toMutableList() ?: ArrayList() 96 | while (true) { 97 | when (val result = parser()) { 98 | is ParseResult.Error -> return result 99 | is ParseResult.NoMatch -> return ParseResult.Success(list) 100 | is ParseResult.Success -> list.add(result.value) 101 | } 102 | } 103 | throw IllegalArgumentException() 104 | } 105 | 106 | 107 | inline fun loop(parser: () -> ParseResult): ParseResult { 108 | var previous = parser() 109 | while (true) { 110 | when (previous) { 111 | ParseResult.Error -> return ParseResult.Error 112 | is ParseResult.NoMatch -> return previous 113 | is ParseResult.Success -> when (val b = parser()) { 114 | ParseResult.Error -> return ParseResult.Error 115 | is ParseResult.NoMatch -> return previous 116 | is ParseResult.Success -> previous = b 117 | } 118 | } 119 | } 120 | } 121 | 122 | inline fun manyUntil(parser: () -> ParseResult, end: TokenType): ParseResult, Token>> { 123 | if (consumeIfMatch(end)) return success(Pair(emptyList(), previous)) 124 | val list = ArrayList() 125 | do { 126 | list.add( 127 | when (val result = expect(parser())) { 128 | is ParseResult.Error -> return result 129 | is ParseResult.NoMatch -> return result 130 | is ParseResult.Success -> result.value 131 | } 132 | ) 133 | } while (!isNext(end)) 134 | expect(end) ?: return ParseResult.Error 135 | return success(Pair(list, previous)) 136 | } 137 | 138 | inline fun manySeparatedUntil(parser: () -> ParseResult, separator: TokenType, end: TokenType): ParseResult, Token>> { 139 | if (consumeIfMatch(end)) return success(Pair(emptyList(), previous)) 140 | val list = ArrayList() 141 | do { 142 | list.add( 143 | when (val result = expect(parser())) { 144 | is ParseResult.Error -> return result 145 | is ParseResult.NoMatch -> return result 146 | is ParseResult.Success -> result.value 147 | } 148 | ) 149 | } while (consumeIfMatch(separator)) 150 | expect(separator, end) ?: return ParseResult.Error 151 | return success(Pair(list, previous)) 152 | } 153 | 154 | inline fun manyTrailingUntil( 155 | parser: () -> ParseResult, 156 | separator: TokenType, 157 | end: TokenType 158 | ): ParseResult, Token>> { 159 | if (consumeIfMatch(end)) return success(Pair(emptyList(), previous)) 160 | val list = ArrayList() 161 | do { 162 | list.add( 163 | when (val result = expect(parser())) { 164 | is ParseResult.Error -> return result 165 | is ParseResult.NoMatch -> return result 166 | is ParseResult.Success -> result.value 167 | } 168 | ) 169 | } while (consumeIfMatch(separator) && !isNext(end)) 170 | expect(separator, end) ?: return ParseResult.Error 171 | return success(Pair(list, previous)) 172 | } 173 | 174 | inline fun manyTrailing( 175 | parser: () -> ParseResult, 176 | separator: TokenType, 177 | ): ParseResult> { 178 | val list = ArrayList() 179 | do { 180 | list.add( 181 | when (val result = expect(parser())) { 182 | is ParseResult.Error -> return result 183 | is ParseResult.NoMatch -> return success(list) 184 | is ParseResult.Success -> result.value 185 | } 186 | ) 187 | } while (consumeIfMatch(separator)) 188 | return success(list) 189 | } 190 | 191 | fun ParseResult.error(createError: () -> CompilerError): ParseResult { 192 | return when (this) { 193 | ParseResult.Error -> this 194 | is ParseResult.NoMatch -> ParseResult.NoMatch(createError()) 195 | is ParseResult.Success -> this 196 | } 197 | } 198 | 199 | fun ParseResult.errorIf(boolean: Boolean, createError: () -> CompilerError): ParseResult { 200 | return if (boolean) when (this) { 201 | ParseResult.Error -> this 202 | is ParseResult.NoMatch -> ParseResult.NoMatch(createError()) 203 | is ParseResult.Success -> this 204 | } else this 205 | } 206 | 207 | 208 | // tokenization 209 | private fun consume(): Token { 210 | previous = current 211 | current = lexer.scanToken() 212 | return previous 213 | } 214 | 215 | private fun expect(type: TokenType) = 216 | if (!consumeIfMatch(type)) { 217 | zinc.reportCompileError(CompilerError.unexpectedToken(current, type)) 218 | null 219 | } else previous 220 | 221 | private fun expect(vararg types: TokenType) = 222 | if (!consumeIfMatch(types)) { 223 | zinc.reportCompileError(CompilerError.unexpectedToken(current, types)) 224 | null 225 | } else previous 226 | 227 | 228 | private fun consumeIfMatch(type: TokenType) = 229 | if (isNext(type)) { 230 | consume() 231 | true 232 | } else false 233 | 234 | private fun consumeIfMatch(types: Array) = 235 | if (isNext(types)) { 236 | consume() 237 | true 238 | } else false 239 | 240 | 241 | private fun atEnd() = isNext(EOF) 242 | 243 | fun isNext(type: TokenType) = current.type == type 244 | fun isPrevious(type: TokenType) = previous.type == type 245 | 246 | private fun isNext(types: Array) = current.type in types 247 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/dsr/ASTContextualizer.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.dsr 2 | 3 | import com.light672.zinc.CompilerError 4 | import com.light672.zinc.Zinc 5 | import com.light672.zinc.ast.Token 6 | import com.light672.zinc.ast.Expr as ASTExpr 7 | import com.light672.zinc.ast.FunctionParam as ASTFunctionParam 8 | import com.light672.zinc.ast.GenericParams as ASTGenericParams 9 | import com.light672.zinc.ast.Pattern as ASTPattern 10 | import com.light672.zinc.ast.Stmt as ASTStmt 11 | 12 | internal class ASTContextualizer(val zinc: Zinc.Runtime) { 13 | 14 | /** 15 | * @param stmt The AST statement being declared in scope and converted into DSR. 16 | * @param types The type branch of the scope the statement is being declared in. 17 | * @param values The value branch of the scope the statement is being declared in. 18 | * @param env The name of the environment the statement is being declared in. For example "scope" or "module". Used for error purposes. 19 | * @return The converted AST statement as a DSR statement containing scope and item information. 20 | */ 21 | private fun stmt(stmt: ASTStmt, types: Branch, values: Branch, env: String): Stmt { 22 | return when (stmt) { 23 | is ASTStmt.Module -> { 24 | val item = Module(stmt, Branch(), Branch()) 25 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, types, env) 26 | module(stmt, item) 27 | } 28 | 29 | is ASTStmt.Trait -> { 30 | val item = Trait(stmt) 31 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, types, env) 32 | trait(stmt) 33 | } 34 | 35 | is ASTStmt.Struct -> { 36 | val item = Struct(stmt) 37 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, types, env) 38 | struct(stmt) 39 | } 40 | 41 | is ASTStmt.TupleStruct -> { 42 | val item = TupleStruct(stmt) 43 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, types, env) 44 | tupleStruct(stmt) 45 | } 46 | 47 | is ASTStmt.UnitStruct -> { 48 | val item = UnitStruct(stmt) 49 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, types, env) 50 | addToBranch(stmt.name.lexeme, stmt.range(), item, values, env) 51 | unitStruct(stmt) 52 | } 53 | 54 | is ASTStmt.Function -> { 55 | val item = Function(stmt) 56 | addToBranch(stmt.name.lexeme!!, stmt.range(), item, values, env) 57 | function(stmt) 58 | } 59 | 60 | is ASTStmt.Expression -> Stmt.Expression(expr(stmt.expr), stmt) 61 | 62 | 63 | is ASTStmt.Implementation -> implementation(stmt) 64 | is ASTStmt.Let -> let(stmt) 65 | 66 | 67 | } 68 | } 69 | 70 | 71 | /** 72 | * @param module The AST module statement being converted into DSR. 73 | * @return The converted AST module as a DSR module containing scope information. 74 | */ 75 | private fun module(module: ASTStmt.Module, item: Module): Stmt.Module { 76 | val stmts = module.statements.map { stmt -> stmt(stmt, item.types, item.values, "module") } 77 | return Stmt.Module(item.types, item.values, stmts, module) 78 | } 79 | 80 | /** 81 | * @param trait The AST trait statement being converted into DSR. 82 | * @return The converted AST trait as a DSR trait containing scope information. 83 | */ 84 | private fun trait(trait: ASTStmt.Trait): Stmt.Trait { 85 | val genericParams = trait.genericParams?.let { params -> genericParams(params) } 86 | val stmts = trait.statements.map { stmt -> 87 | when (stmt) { 88 | is ASTStmt.Function -> function(stmt, genericParams?.branch) 89 | } 90 | } 91 | return Stmt.Trait(genericParams, stmts, trait) 92 | } 93 | 94 | /** 95 | * @param struct The AST struct statement being converted into DSR. 96 | * @return The converted AST struct as a DSR struct containing scope information. 97 | */ 98 | private fun struct(struct: ASTStmt.Struct): Stmt.Struct { 99 | val genericParams = struct.genericParams?.let { params -> genericParams(params) } 100 | return Stmt.Struct(genericParams, struct) 101 | } 102 | 103 | /** 104 | * @param struct The AST unit struct statement being converted into DSR. 105 | * @return The converted AST unit struct as a DSR unit struct containing scope information. 106 | */ 107 | private fun unitStruct(struct: ASTStmt.UnitStruct): Stmt.UnitStruct { 108 | val genericParams = struct.genericParams?.let { params -> genericParams(params) } 109 | return Stmt.UnitStruct(genericParams, struct) 110 | } 111 | 112 | /** 113 | * @param struct The AST tuple struct statement being converted into DSR. 114 | * @return The converted AST tuple struct as a DSR tuple struct containing scope information. 115 | */ 116 | private fun tupleStruct(struct: ASTStmt.TupleStruct): Stmt.TupleStruct { 117 | val genericParams = struct.genericParams?.let { params -> genericParams(params) } 118 | return Stmt.TupleStruct(genericParams, struct) 119 | } 120 | 121 | /** 122 | * @param function The AST function statement being converted into DSR. 123 | * @param parentGenericBranch The type branch containing the generic parameters defined by an implementation or trait. For functions declared outside impls or traits, its default value is null. 124 | * @return The converted AST function as a DSR function containing scope information. 125 | */ 126 | private fun function(function: ASTStmt.Function, parentGenericBranch: Branch? = null): Stmt.Function { 127 | val genericParams = function.genericParams?.let { params -> genericParams(params, parentGenericBranch) } 128 | val paramBranch = Branch() 129 | val params = function.params.map { param -> 130 | when (param) { 131 | is ASTFunctionParam.Pattern -> FunctionParam.Pattern(pattern(param.pattern, paramBranch), param) 132 | is ASTFunctionParam.Self -> { 133 | val selfItem = Self(param) 134 | addToBranch("self", param.self.asRange(), selfItem, paramBranch, "function parameters") 135 | FunctionParam.Self(selfItem, param) 136 | } 137 | } 138 | } 139 | val block = function.block?.let { block -> block(block) } 140 | return Stmt.Function(genericParams, paramBranch, params, block, function) 141 | } 142 | 143 | /** 144 | * @param impl The AST implementation statement being converted into DSR. 145 | * @return The converted AST implementation as a DSR implementation containing scope information. 146 | */ 147 | private fun implementation(impl: ASTStmt.Implementation): Stmt.Implementation { 148 | val genericParams = impl.genericParams?.let { params -> genericParams(params) } 149 | val stmts = impl.statements.map { stmt -> 150 | when (stmt) { 151 | is ASTStmt.Function -> function(stmt, genericParams?.branch) 152 | } 153 | } 154 | 155 | return Stmt.Implementation(genericParams, stmts, impl) 156 | } 157 | 158 | /** 159 | * @param let The AST let statement being converted into DSR. 160 | */ 161 | private fun let(let: ASTStmt.Let): Stmt.Let { 162 | val branch = Branch() 163 | val pattern = pattern(let.pattern, branch) 164 | val initializer = let.initializer?.let { expr -> expr(expr) } 165 | return Stmt.Let(branch, pattern, initializer, let) 166 | } 167 | 168 | 169 | /** 170 | * @param genericParams The AST generic parameters being converted into DSR. 171 | * @param parentGenericBranch The type branch containing the generic parameters defined by an implementation or trait if inside one. 172 | * @return The converted AST generic parameters as DSR generic parameters containing generic items. 173 | */ 174 | private fun genericParams(genericParams: ASTGenericParams, parentGenericBranch: Branch? = null): GenericParams { 175 | val genericScope = Branch() 176 | val generics = genericParams.params.withIndex().map { (index, param) -> 177 | val item = Generic(index, param.name) 178 | addGenericToBranch(param.name, item, genericScope, parentGenericBranch) 179 | item 180 | } 181 | 182 | return GenericParams(generics, genericScope, genericParams) 183 | } 184 | 185 | /** 186 | * @param expr The AST expression being declared in scope and converted into DSR. 187 | * @return The converted AST expression as a DSR expression containing scope and item information. 188 | */ 189 | private fun expr(expr: ASTExpr): Expr { 190 | return when (expr) { 191 | is ASTExpr.Binary -> Expr.Binary(expr(expr.left), expr(expr.right), expr) 192 | is ASTExpr.Block -> block(expr) 193 | is ASTExpr.Break -> Expr.Break(expr.expr?.let { value -> expr(value) }, expr) 194 | is ASTExpr.Call -> Expr.Call(expr(expr.callee), expr.args.map { arg -> expr(arg) }, expr) 195 | is ASTExpr.Closure -> closure(expr) 196 | is ASTExpr.Continue -> Expr.Continue(expr) 197 | is ASTExpr.FieldGet -> Expr.FieldGet(expr(expr.callee), expr) 198 | is ASTExpr.For -> forExpr(expr) 199 | is ASTExpr.Group -> Expr.Group(expr.expressions.map { field -> expr(field) }, expr) 200 | is ASTExpr.If -> Expr.If(expr(expr.condition), block(expr.thenBlock), expr.elseExpr?.let { elseExpr -> expr(elseExpr) }, expr) 201 | is ASTExpr.Index -> Expr.Index(expr(expr.callee), expr.args.map { arg -> expr(arg) }, expr) 202 | is ASTExpr.Literal -> Expr.Literal(expr) 203 | is ASTExpr.Loop -> Expr.Loop(block(expr.block), expr) 204 | is ASTExpr.Match -> match(expr) 205 | is ASTExpr.Path -> Expr.Path(expr) 206 | is ASTExpr.Range -> Expr.Range(expr.left?.let { left -> expr(left) }, expr.right?.let { right -> expr(right) }, expr) 207 | is ASTExpr.Return -> Expr.Return(expr.expr?.let { value -> expr(value) }, expr) 208 | is ASTExpr.Unary -> Expr.Unary(expr(expr.right), expr) 209 | is ASTExpr.While -> Expr.While(expr(expr.condition), block(expr.block), expr) 210 | } 211 | } 212 | 213 | /** 214 | * @param block The AST block expression being converted into DSR. 215 | * @return The converted AST block as a DSR block containing scope information. 216 | */ 217 | private fun block(block: ASTExpr.Block): Expr.Block { 218 | val types = Branch() 219 | val values = Branch() 220 | val stmts = block.stmts.map { stmt -> 221 | stmt(stmt, types, values, "scope") 222 | } 223 | return Expr.Block(types, values, stmts, block) 224 | } 225 | 226 | /** 227 | * @param closure The AST closure expression being converted into DSR. 228 | * @return The converted AST closure as a DSR closure containing scope information. 229 | */ 230 | private fun closure(closure: ASTExpr.Closure): Expr.Closure { 231 | val paramBranch = Branch() 232 | val patterns = closure.params.map { (pattern, type) -> pattern(pattern, paramBranch) } 233 | val expr = expr(closure.expr) 234 | return Expr.Closure(paramBranch, patterns, expr, closure) 235 | } 236 | 237 | /** 238 | * @param forExpr The AST for expression being converted into DSR. 239 | * @return The converted AST for loop as a DSR for loop containing scope information. 240 | */ 241 | private fun forExpr(forExpr: ASTExpr.For): Expr.For { 242 | val patternBranch = Branch() 243 | val pattern = pattern(forExpr.pattern, patternBranch) 244 | val iterator = expr(forExpr.iterator) 245 | val block = block(forExpr.block) 246 | return Expr.For(patternBranch, pattern, iterator, block, forExpr) 247 | } 248 | 249 | /** 250 | * @param match The AST match expression being converted into DSR. 251 | * @return The converted AST match as a DSR match containing scope information. 252 | */ 253 | private fun match(match: ASTExpr.Match): Expr.Match { 254 | val expr = expr(match.expr) 255 | val branches = match.branches.map { (pattern, expr) -> 256 | val patternBranch = Branch() 257 | val pattern = pattern(pattern, patternBranch) 258 | val expr = expr(expr) 259 | Triple(patternBranch, pattern, expr) 260 | } 261 | 262 | return Expr.Match(expr, branches, match) 263 | } 264 | 265 | 266 | /** 267 | * @param pattern The pattern being converted into DSR. 268 | * @param branch The value branch where any variables declared by the pattern are added. 269 | * @return The converted AST pattern as a DSR pattern containing variable items. 270 | */ 271 | private fun pattern(pattern: ASTPattern, branch: Branch): Pattern { 272 | return when (pattern) { 273 | is ASTPattern.Identifier -> { 274 | val variable = Variable(pattern) 275 | addToBranch(pattern.token.lexeme!!, pattern.token.asRange(), variable, branch, "scope") 276 | Pattern.Variable(variable, pattern) 277 | } 278 | 279 | is ASTPattern.Literal -> Pattern.Literal(pattern) 280 | is ASTPattern.Tuple -> Pattern.Tuple(pattern.fields.map { field -> pattern(field, branch) }, pattern) 281 | is ASTPattern.Wildcard -> Pattern.Wildcard(pattern) 282 | } 283 | } 284 | 285 | 286 | /** 287 | * @param name The name of the item being declared in [branch]. 288 | * @param declRange The token range of the declaration statement. Used for error purposes. 289 | * @param item The item being declared under [name] in [branch]. If you are adding a generic, use [addGenericToBranch]. 290 | * @param branch The branch in which the item is declared. 291 | * @param env The name of the environment the item is being declared in. For example "scope" or "module". Used for error purposes. 292 | * 293 | * Reports an error and sets the item under the name as null if an item with the same name already exists in the branch. 294 | */ 295 | private fun addToBranch(name: CharSequence, declRange: Token.Range, item: T, branch: Branch, env: String) { 296 | val toAdd = 297 | if (branch.data.containsKey(name)) { 298 | zinc.reportCompileError(CompilerError.nameAlreadyExists(name, declRange, env)) 299 | null 300 | } else item 301 | 302 | branch.data[name] = toAdd 303 | } 304 | 305 | /** 306 | * @param name The name of the generic declared in the branch 307 | * @param item The generic being declared under [name] in [branch] 308 | * @param branch The branch in which the generic is declared 309 | * @param parentGenericBranch The type branch containing the generic parameters defined by an implementation or trait if inside one. 310 | * 311 | * Reports an error and sets the item under the name as null if an item with the same name already exists in the branch or in the parent generic branch. 312 | */ 313 | private fun addGenericToBranch(name: Token, item: Generic, branch: Branch, parentGenericBranch: Branch?) { 314 | val toAdd = 315 | if (branch.data.containsKey(name.lexeme!!)) { 316 | zinc.reportCompileError(CompilerError.nameAlreadyExists(name.lexeme, name.asRange(), "generic parameters")) 317 | null 318 | } else { 319 | parentGenericBranch?.let { parentBranch -> 320 | if (parentBranch.data.containsKey(name.lexeme)) 321 | zinc.reportCompileError(CompilerError.usedGenericParamNameInItem(name)) 322 | } 323 | item 324 | } 325 | 326 | branch.data[name.lexeme] = toAdd 327 | } 328 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/ast/Parser.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.ast 2 | 3 | import com.light672.zinc.CompilerError 4 | import com.light672.zinc.Zinc 5 | import com.light672.zinc.ast.TokenType.* 6 | 7 | internal class Parser(val zinc: Zinc.Runtime) { 8 | val combinator = CombinatorParser(zinc) 9 | 10 | fun declaration(): ParseResult = with(combinator) { 11 | (function() or ::struct or ::module or ::trait or ::implementation).error { CompilerError.expectedStatement(current) } 12 | } 13 | 14 | fun associatedStmt(): ParseResult = with(combinator) { 15 | (function()).error { CompilerError.expectedAssociatedStatement(current) } 16 | } 17 | 18 | fun trait(): ParseResult = with(combinator) { 19 | val keyword = token(INTERFACE) 20 | val name = keyword 21 | .then { expect(token(IDENTIFIER)) } 22 | val genericParams = name 23 | .then { optional(genericParams()) } 24 | val whereClause = genericParams 25 | .then { optional(where()) } 26 | whereClause 27 | .then { expect(token(LEFT_BRACE)) } 28 | .then { manyUntil(::associatedStmt, RIGHT_BRACE) } 29 | .map { (stmts, close) -> Stmt.Trait(+keyword, +name, +genericParams, +whereClause, stmts) } 30 | } 31 | 32 | fun implementation(): ParseResult = with(combinator) { 33 | val keyword = token(IMPL) 34 | val genericParams = keyword 35 | .then { optional(genericParams()) } 36 | val type = genericParams 37 | .then { expect(type()) } 38 | val trait = type 39 | .then { optional(token(COLON).then { expect(typePath()) }) } 40 | val whereClause = trait 41 | .then { optional(where()) } 42 | 43 | whereClause 44 | .then { expect(token(LEFT_BRACE)) } 45 | .then { manyUntil(::associatedStmt, RIGHT_BRACE) } 46 | .map { (stmts, close) -> Stmt.Implementation(+keyword, +genericParams, +type, +trait, +whereClause, stmts) } 47 | } 48 | 49 | fun function(): ParseResult = with(combinator) { 50 | val keyword = token(FN) 51 | val name = keyword 52 | .then { expect(token(IDENTIFIER)) } 53 | val genericParams = name 54 | .then { optional(genericParams()) } 55 | val params = genericParams.then { 56 | expect(run { 57 | val open = token(LEFT_PAREN) 58 | open 59 | .then { expect(manyTrailingUntil(::functionParam, COMMA, RIGHT_PAREN)) } 60 | .map { (list, close) -> Triple(+open, list, close) } 61 | }) 62 | } 63 | val returnType = params.then { optional(token(MINUS_ARROW).then { expect(type()) }) } 64 | val whereClause = returnType.then { optional(where()) } 65 | val functionNoBlock = 66 | token(SEMICOLON).map { _ -> 67 | Stmt.Function(+keyword, +name, +genericParams, (+params).second, (+params).third, +returnType, +whereClause, null) 68 | } 69 | 70 | val functionWithBlockParser = 71 | { 72 | block(null).map { block -> 73 | Stmt.Function(+keyword, +name, +genericParams, (+params).second, (+params).third, +returnType, +whereClause, block) 74 | } 75 | } 76 | whereClause 77 | .then { expect(functionNoBlock or functionWithBlockParser) } 78 | } 79 | 80 | fun functionParam() = with(combinator) { 81 | val selfParser = { 82 | val token = token(SELF) 83 | token 84 | .then { optional(token(COLON).then { expect(type()) }) } 85 | .map { type -> FunctionParam.Self(+token, type) } 86 | } 87 | 88 | val patternParser = { patternAndType().map { (pattern, type) -> FunctionParam.Pattern(pattern, type) } } 89 | 90 | selfParser() or patternParser 91 | } 92 | 93 | fun struct(): ParseResult = with(combinator) { 94 | val keyword = token(STRUCT) 95 | val name = keyword 96 | .then { expect(token(IDENTIFIER)) } 97 | val genericParams = name 98 | .then { optional(genericParams()) } 99 | 100 | val whereClause = genericParams.then { optional(where()) } 101 | 102 | val structFieldParser = { 103 | val name = token(IDENTIFIER) 104 | name 105 | .then { expect(token(COLON)) } 106 | .then { expect(type()) } 107 | .map { type -> Pair(+name, type) } 108 | } 109 | 110 | val structParser = { 111 | token(LEFT_BRACE) 112 | .then { manyTrailingUntil(structFieldParser, COMMA, RIGHT_BRACE) } 113 | .map { (list, close) -> Stmt.Struct(+keyword, +name, +genericParams, list, +whereClause, close) } 114 | } 115 | val tupleParser = { 116 | val result = token(LEFT_PAREN) 117 | .then { manyTrailingUntil(::type, COMMA, RIGHT_PAREN) } 118 | .map { (list, close) -> Stmt.TupleStruct(+keyword, +name, +genericParams, list, +whereClause, close) } 119 | result 120 | .then { expect(token(SEMICOLON)) } 121 | .flatMap { result } 122 | } 123 | val unitParser = { token(SEMICOLON).map { semicolon -> Stmt.UnitStruct(+keyword, +name, +genericParams, +whereClause, semicolon) } } 124 | 125 | whereClause 126 | .then { expect(structParser() or tupleParser or unitParser) } 127 | } 128 | 129 | fun module(): ParseResult = with(combinator) { 130 | val keyword = token(MOD) 131 | val name = keyword 132 | .then { expect(token(IDENTIFIER)) } 133 | name 134 | .then { expect(token(LEFT_BRACE)) } 135 | .then { expect(manyUntil(::declaration, RIGHT_BRACE)) } 136 | .map { (list, close) -> Stmt.Module(+keyword, +name, list, close) } 137 | } 138 | 139 | fun let(): ParseResult = with(combinator) { 140 | val keyword = token(LET) 141 | val patternAndType = keyword 142 | .then { expect(patternAndOptionalType()) } 143 | 144 | val initializer = patternAndType 145 | .then { optional(token(EQUAL).then { expect(expression()) }) } 146 | 147 | initializer.then { 148 | expect(token(SEMICOLON)) 149 | .map { Stmt.Let(+keyword, (+patternAndType).first, (+patternAndType).second, +initializer) } 150 | } 151 | } 152 | 153 | 154 | // expressions 155 | 156 | fun exprWithLabel(): ParseResult = with(combinator) { 157 | val label = token(IDENTIFIER) 158 | if (label.isSuccess() && !isNext(COLON)) return label.flatMap { begin -> exprPath(begin) } 159 | 160 | 161 | val parser = { label: Token? -> ifExpr(label) or { whileExpr(label) } or { loop(label) } or { forExpr(label) } or { block(label) } } 162 | 163 | label 164 | .then { 165 | expect(token(COLON)) 166 | .then { expect(parser(+label).error { CompilerError.expectedBlockExpr(current) }) } 167 | } 168 | .or { parser(null) } 169 | } 170 | 171 | fun expression(): ParseResult = with(combinator) { 172 | assignment().error { CompilerError.expectedExpression(current) } 173 | } 174 | 175 | fun ifExpr(label: Token?) = with(combinator) { 176 | fun ifParser(keyword: Token): ParseResult { 177 | fun elseParser(): ParseResult { 178 | return token(ELSE) 179 | .then { 180 | token(IF).flatMap { t -> ifParser(t) } or { block(null) } 181 | } 182 | } 183 | 184 | val condition = expect(expression()) 185 | val block = condition 186 | .then { expect(block(null)) } 187 | return block 188 | .then { optional(elseParser()) } 189 | .map { elseExpr -> Expr.If(label, keyword, +condition, +block, elseExpr) } 190 | } 191 | 192 | token(IF).flatMap { token -> ifParser(token) } 193 | } 194 | 195 | fun whileExpr(label: Token?) = with(combinator) { 196 | val keyword = token(WHILE) 197 | val condition = keyword 198 | .then { expect(expression()) } 199 | condition 200 | .then { expect(block(null)) } 201 | .map { block -> Expr.While(label, +keyword, +condition, block) } 202 | } 203 | 204 | fun loop(label: Token?) = with(combinator) { 205 | val keyword = token(LOOP) 206 | keyword 207 | .then { expect(block(null)) } 208 | .map { block -> Expr.Loop(label, +keyword, block) } 209 | } 210 | 211 | fun forExpr(label: Token?) = with(combinator) { 212 | val keyword = token(FOR) 213 | val pattern = keyword 214 | .then { expect(pattern()) } 215 | val iterator = pattern 216 | .then { expect(token(IN)) } 217 | .then { expect(expression()) } 218 | iterator 219 | .then { expect(block(null)) } 220 | .map { block -> Expr.For(label, +keyword, +pattern, +iterator, block) } 221 | } 222 | 223 | fun match() = with(combinator) { 224 | val branchParser = { 225 | val pattern = pattern() 226 | pattern 227 | .then { expect(token(EQUALS_ARROW)) } 228 | .then { expect(expression()) } 229 | .map { expr -> Pair(+pattern, expr) } 230 | } 231 | 232 | val keyword = token(MATCH) 233 | val expr = keyword 234 | .then { expect(expression()) } 235 | expr 236 | .then { expect(token(LEFT_BRACE)) } 237 | .then { expect(manyTrailingUntil(branchParser, COMMA, RIGHT_BRACE)) } 238 | .map { (branches, close) -> Expr.Match(+keyword, +expr, branches, close) } 239 | } 240 | 241 | fun primary() = with(combinator) { 242 | val group = { 243 | val open = token(LEFT_PAREN) 244 | open 245 | .then { expect(manySeparatedUntil(::expression, COMMA, RIGHT_PAREN)) } 246 | .map { (list, close) -> Expr.Group(+open, list, close) } 247 | } 248 | val literal = { 249 | token( 250 | NUMBER, 251 | STRING, 252 | TRUE, 253 | FALSE 254 | ).map { Expr.Literal(it) } 255 | } 256 | 257 | group() or 258 | literal or 259 | { qualifiedPath().map { path -> Expr.Path(path) } } or 260 | ::returnExpr or 261 | ::breakExpr or 262 | ::continueExpr or 263 | ::closure or 264 | ::match or 265 | ::exprWithLabel 266 | } 267 | 268 | fun args(open: TokenType, close: TokenType): ParseResult, Token>> { 269 | return with(combinator) { 270 | val openToken = token(open) 271 | openToken 272 | .then { expect(manyTrailingUntil(::expression, COMMA, close)) } 273 | .map { (list, closeToken) -> Triple(+openToken, list, closeToken) } 274 | } 275 | } 276 | 277 | fun call(): ParseResult = with(combinator) { 278 | primary().flatMap { expr -> callPrime(expr) } 279 | } 280 | 281 | fun callPrime(callee: Expr): ParseResult = with(combinator) { 282 | val callArgs = { args(LEFT_PAREN, RIGHT_PAREN).map { (open, args, close) -> Expr.Call(callee, open, args, close) } } 283 | val indexArgs = { args(LEFT_BRACKET, RIGHT_BRACKET).map { (open, args, close) -> Expr.Index(callee, open, args, close) } } 284 | val dot = { token(DOT).then { expect(fieldSegment()) }.map { seg -> Expr.FieldGet(callee, seg) } } 285 | 286 | val args = { callArgs() or indexArgs or dot } 287 | 288 | args().flatMap { expr -> callPrime(expr) } or { success(callee) } 289 | } 290 | 291 | 292 | fun unary(): ParseResult = with(combinator) { 293 | val operator = token(MINUS, BANG, TILDA) 294 | val unary = operator 295 | .then(::unary) 296 | .map { expr -> Expr.Unary(+operator, expr) } 297 | 298 | unary or ::call 299 | } 300 | 301 | fun cast(): ParseResult = 302 | binary(::unary, ::cast, AS) 303 | 304 | fun factor(): ParseResult = 305 | binary(::cast, ::factor, STAR, SLASH, PERCENT) 306 | 307 | fun term(): ParseResult = 308 | binary(::factor, ::term, PLUS, MINUS) 309 | 310 | fun range(): ParseResult = with(combinator) { 311 | val left = optional(term()) 312 | val rightParser = { 313 | val operator = token(DOT_DOT) 314 | operator 315 | .then { optional(range()) } 316 | .map { expr -> Expr.Range(+left, +operator, expr) } 317 | } 318 | 319 | left 320 | .then { optional(rightParser()) } 321 | .flatMap { it?.let { success(it) } ?: (+left)?.let { success(it) } ?: noMatch(CompilerError.expectedExpression(current)) } 322 | } 323 | 324 | fun shift(): ParseResult = 325 | binary(::range, ::shift) // TODO: lex << >> >>> 326 | 327 | fun bitAnd(): ParseResult = 328 | binary(::shift, ::bitAnd, AMP) 329 | 330 | fun xor(): ParseResult = 331 | binary(::bitAnd, ::xor, CARET) 332 | 333 | fun bitOr(): ParseResult = 334 | binary(::xor, ::bitOr, PIPE) 335 | 336 | fun comparison(): ParseResult = 337 | binary(::bitOr, ::comparison, EQUAL_EQUAL, BANG_EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL) 338 | 339 | fun and(): ParseResult = 340 | binary(::comparison, ::and, AMP_AMP) 341 | 342 | fun or(): ParseResult = 343 | binary(::and, ::or, PIPE_PIPE) 344 | 345 | fun assignment(): ParseResult = // TODO: lex <<= >>= >>>= 346 | binary(::or, ::assignment, EQUAL, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL, SLASH_EQUAL, PERCENT_EQUAL, PIPE_EQUAL, AMP_EQUAL, CARET_EQUAL) 347 | 348 | 349 | inline fun binary(left: () -> ParseResult, crossinline right: () -> ParseResult, vararg symbols: TokenType) = with(combinator) { 350 | val left = left() 351 | 352 | val rightParser = { 353 | val operator = token(*symbols) 354 | operator 355 | .then { expect(right()) } 356 | .map { expr -> Expr.Binary(+left, +operator, expr) } 357 | } 358 | 359 | left 360 | .then { optional(rightParser()) } 361 | .map { it ?: +left } 362 | } 363 | 364 | fun returnExpr() = with(combinator) { 365 | val keyword = token(RETURN) 366 | keyword 367 | .then { optional(expression()) } 368 | .map { expr -> Expr.Return(+keyword, expr) } 369 | } 370 | 371 | fun breakExpr() = with(combinator) { 372 | val keyword = token(BREAK) 373 | val label = keyword 374 | .then { optional(token(AT).then { expect(token(IDENTIFIER)) }) } 375 | label 376 | .then { optional(expression()) } 377 | .map { expr -> Expr.Break(+keyword, +label, expr) } 378 | } 379 | 380 | fun continueExpr() = with(combinator) { 381 | val keyword = token(CONTINUE) 382 | keyword 383 | .then { optional(token(AT).then { expect(token(IDENTIFIER)) }) } 384 | .map { label -> Expr.Continue(+keyword, label) } 385 | } 386 | 387 | fun closure(): ParseResult = with(combinator) { 388 | val beginNoArgs = { 389 | val doublePipe = token(PIPE_PIPE) 390 | doublePipe.map { token -> Triple(token, emptyList>(), token) } 391 | } 392 | val beginArgs = { 393 | val open = token(PIPE) 394 | open 395 | .then { expect(manyTrailingUntil(::patternAndOptionalType, COMMA, PIPE)) } 396 | .map { (list, close) -> Triple(+open, list, close) } 397 | } 398 | val params = (beginArgs() or beginNoArgs) 399 | 400 | val returnTypeParser = { 401 | val type = token(MINUS_ARROW).then { expect(type()) } 402 | type.then { expect(block(null)) } 403 | .map { block -> Pair(+type, block) } 404 | } 405 | 406 | val withoutReturnType = { 407 | expression() 408 | .map { expr -> Pair(null, expr) } 409 | } 410 | 411 | val returnTypeAndExpr = params 412 | .then { returnTypeParser() or withoutReturnType } 413 | returnTypeAndExpr 414 | .map { (type, expr) -> (+params).let { (open, list, close) -> Expr.Closure(open, list, close, type, expr) } } 415 | } 416 | 417 | fun block(label: Token?): ParseResult = with(combinator) { 418 | fun trailingCheck(expr: Expr) = 419 | when (expr) { 420 | is Expr.Block, 421 | is Expr.Loop, 422 | is Expr.If -> Stmt.Expression(expr, null) 423 | 424 | else -> { 425 | val semicolon = token(SEMICOLON) 426 | if (semicolon.isSuccess()) Stmt.Expression(expr, +semicolon) 427 | else { 428 | val expr = Stmt.Expression(expr, null) 429 | if (!isNext(RIGHT_BRACE)) { 430 | expect(token(SEMICOLON)) // create error message 431 | null 432 | } else expr 433 | } 434 | } 435 | } 436 | 437 | 438 | val open = token(LEFT_BRACE) 439 | open 440 | .then { 441 | expect( 442 | manyUntil( 443 | { declaration() or ::let or { expression().flatMap { trailingCheck(it)?.let { success(it) } ?: failure() } } }, 444 | RIGHT_BRACE 445 | ) 446 | ) 447 | } 448 | .map { (list, close) -> Expr.Block(label, +open, list, close) } 449 | 450 | } 451 | 452 | 453 | // patterns 454 | fun pattern(): ParseResult = with(combinator) { 455 | (pathPattern() or ::wildCard or ::literalPattern or ::tuplePattern) 456 | .error { CompilerError.expectedPattern(current) } 457 | } 458 | 459 | fun pathPattern() = with(combinator) { token(IDENTIFIER).map { t -> Pattern.Identifier(t) } } 460 | fun wildCard() = with(combinator) { token(UNDERSCORE).map { t -> Pattern.Wildcard(t) } } 461 | fun literalPattern() = with(combinator) { token(NUMBER, STRING, TRUE, FALSE).map { t -> Pattern.Literal(t) } } 462 | fun tuplePattern() = with(combinator) { 463 | val open = token(LEFT_PAREN) 464 | open 465 | .then { expect(manyTrailingUntil(::pattern, COMMA, RIGHT_PAREN)) } 466 | .map { (list, close) -> Pattern.Tuple(+open, list, close) } 467 | } 468 | 469 | fun patternAndType(): ParseResult> = with(combinator) { 470 | val pattern = pattern() 471 | pattern 472 | .then { expect(token(COLON)) } 473 | .then { expect(type()) } 474 | .map { type -> Pair(+pattern, type) } 475 | } 476 | 477 | fun patternAndOptionalType(): ParseResult> = with(combinator) { 478 | val pattern = pattern() 479 | pattern 480 | .then { optional(token(COLON).then { expect(type()) }) } 481 | .map { type -> Pair(+pattern, type) } 482 | } 483 | 484 | // types 485 | fun type(): ParseResult = with(combinator) { 486 | val tupleParser = { 487 | val open = token(LEFT_PAREN) 488 | open 489 | .then { expect(manyTrailingUntil({ expect(type()) }, COMMA, RIGHT_PAREN)) } 490 | .map { (list, close) -> Type.Tuple(+open, list, close) } 491 | } 492 | 493 | (tupleParser() or { complexPath().map { path -> Type.Path(path) } }) 494 | .error { CompilerError.expectedType(current) } 495 | } 496 | 497 | fun genericArgs(): ParseResult = with(combinator) { 498 | val open = token(LESS) 499 | open 500 | .then { expect(manyTrailingUntil({ expect(type()) }, COMMA, GREATER)) } 501 | .map { (list, close) -> GenericArgs(+open, list, close) } 502 | } 503 | 504 | fun genericParams(): ParseResult = with(combinator) { 505 | val open = token(LESS) 506 | val typeParamParser = { 507 | val identifier = token(IDENTIFIER) 508 | identifier 509 | .then { optional(token(COLON).then { expect(typeParamBound()) }) } 510 | .map { bounds -> GenericParam(+identifier, bounds) } 511 | } 512 | open 513 | .then { expect(manyTrailingUntil(typeParamParser, COMMA, GREATER)) } 514 | .map { (list, close) -> GenericParams(+open, list, close) } 515 | } 516 | 517 | fun where(): ParseResult = with(combinator) { 518 | val keyword = token(WHERE) 519 | val clauseParser = { 520 | val type = type() 521 | val bounds = type 522 | .then { expect(token(COLON)).then { expect(typeParamBound()) } } 523 | bounds.map { bounds -> WhereClauseItem(+type, bounds) } 524 | } 525 | val first = clauseParser() 526 | first 527 | .then { manyTrailing(clauseParser, COMMA) } 528 | .map { clauseItems -> WhereClause(+keyword, clauseItems) } 529 | } 530 | 531 | fun typeParamBound(): ParseResult = with(combinator) { 532 | val first = typePath() 533 | first 534 | .then { many({ token(AMP).then { expect(typePath()) } }, listOf(+first)) } 535 | .map { list -> TypeParamBounds(list) } 536 | } 537 | 538 | // paths 539 | 540 | fun path(segmentParser: () -> ParseResult) = path(segmentParser, segmentParser) 541 | 542 | fun path(beginParser: () -> ParseResult, restParser: () -> ParseResult) = with(combinator) { 543 | val list = ArrayList() 544 | 545 | var topSegment = beginParser() 546 | if (!topSegment.isSuccess()) return ParseResult.NoMatch(CompilerError.EMPTY) 547 | list.add(+topSegment) 548 | 549 | while (isPrevious(COLON_COLON)) 550 | topSegment = topSegment 551 | .then { expect(restParser()) } 552 | .with { seg -> list.add(seg) } 553 | 554 | topSegment 555 | .flatMap { success(ComplexPath.Normal(list)) } 556 | } 557 | 558 | fun typePath() = path(::pathSegment) 559 | fun exprPath(beginToken: Token) = with(combinator) { 560 | path({ exprPathSegment(beginToken) }, ::exprPathSegment) 561 | .map { path -> Expr.Path(path) } 562 | } 563 | 564 | 565 | fun qualifiedPath() = with(combinator) { 566 | val asParser = { token(AS).then { expect(typePath()) } } 567 | 568 | val openToken = token(LESS) 569 | val type = openToken 570 | .then { expect(type()) } 571 | val trait = type 572 | .then { optional(asParser()) } 573 | val close = trait 574 | .then { expect(token(GREATER)) } 575 | close 576 | .then { expect(token(COLON_COLON)) } 577 | .then { expect(typePath()) } 578 | .map { typePath -> ComplexPath.Qualified(+openToken, +type, +trait, +close, typePath.body) } 579 | 580 | } 581 | 582 | fun complexPath(): ParseResult = with(combinator) { 583 | qualifiedPath() or ::typePath 584 | } 585 | 586 | fun pathSegment(): ParseResult = with(combinator) { 587 | val identifier = token(IDENTIFIER) 588 | identifier 589 | .then { optional(token(COLON_COLON)) } // consumes the `::` in between ident and generics if people use that for some reason 590 | .then { optional(genericArgs().with { token(COLON_COLON) }) } // consumes terminator `::` after generic args if present 591 | .map { generics -> ComplexSegment(+identifier, generics) } 592 | } 593 | 594 | 595 | // only difference between this and `pathSegment` is that a `::` must be present before parsing any generics 596 | fun exprPathSegment(identifier: Token? = null): ParseResult = with(combinator) { 597 | val identifier = identifier?.let { success(it) } ?: token(IDENTIFIER) 598 | identifier 599 | .then { optional(token(COLON_COLON).then { optional(genericArgs().with { token(COLON_COLON) }) }) } // consumes terminator `::` after generic args if present 600 | .map { generics -> ComplexSegment(+identifier, generics) } 601 | } 602 | 603 | fun fieldSegment(): ParseResult = with(combinator) { 604 | val identifier = token(IDENTIFIER) 605 | identifier 606 | .then { optional(token(COLON_COLON).then { expect(genericArgs()) }) } 607 | .map { generics -> ComplexSegment(+identifier, generics) } 608 | } 609 | 610 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/light672/zinc/hir/Resolver.kt: -------------------------------------------------------------------------------- 1 | package com.light672.zinc.hir 2 | 3 | import com.light672.zinc.CompilerError 4 | import com.light672.zinc.Zinc 5 | import com.light672.zinc.ast.ComplexPath 6 | import com.light672.zinc.ast.ComplexSegment 7 | import com.light672.zinc.ast.Token 8 | import com.light672.zinc.dsr.* 9 | import com.light672.zinc.hir.AssociatedStmt 10 | import com.light672.zinc.hir.Expr 11 | import com.light672.zinc.hir.FunctionParam 12 | import com.light672.zinc.hir.Pattern 13 | import com.light672.zinc.hir.Stmt 14 | import com.light672.zinc.ast.GenericArgs as ASTGenericArgs 15 | import com.light672.zinc.ast.Type as ASTType 16 | import com.light672.zinc.ast.TypeParamBounds as ASTTypeParamBounds 17 | import com.light672.zinc.ast.WhereClause as ASTWhereClause 18 | import com.light672.zinc.dsr.AssociatedStmt as DSRAssociatedStmt 19 | import com.light672.zinc.dsr.Expr as DSRExpr 20 | import com.light672.zinc.dsr.FunctionParam as DSRFunctionParam 21 | import com.light672.zinc.dsr.GenericParams as DSRGenericParams 22 | import com.light672.zinc.dsr.Pattern as DSRPattern 23 | import com.light672.zinc.dsr.Stmt as DSRStmt 24 | 25 | private typealias Values = Resolver.BranchNode 26 | private typealias Types = Resolver.BranchNode 27 | 28 | internal class Resolver(val zinc: Zinc.Runtime) { 29 | data class BranchNode(val branch: Branch, val indexSinceDecl: Int, val next: BranchNode?) 30 | 31 | /** 32 | * @param stmt The DSR statement being converted into HIR. 33 | * @param values The value scope being used to resolve the statement. 34 | * @param types The type scope being used to resolve the statement. 35 | * @return The converted DSR statement as a HIR statement containing resolved names as well as the next value branch that should be used. 36 | */ 37 | fun stmt(stmt: DSRStmt, values: Values, types: Types): Pair { 38 | return when (stmt) { 39 | is DSRStmt.Function -> Pair(function(stmt, values, types, false), values) 40 | is DSRStmt.Expression -> Pair(Stmt.Expression(expr(stmt.expr, values, types), stmt.ast), values) 41 | is DSRStmt.Implementation -> Pair(implementation(stmt, values, types), values) 42 | is DSRStmt.Let -> let(stmt, values, types) 43 | is DSRStmt.Module -> Pair(module(stmt), values) 44 | is DSRStmt.Trait -> Pair(trait(stmt, values, types), values) 45 | is DSRStmt.Struct -> Pair(struct(stmt, types), values) 46 | is DSRStmt.TupleStruct -> Pair(tupleStruct(stmt, types), values) 47 | is DSRStmt.UnitStruct -> Pair(unitStruct(stmt, types), values) 48 | } 49 | } 50 | 51 | /** 52 | * @param stmt The DSR associated statement being converted into HIR. 53 | * @param values The value scope being used to resolve the statement. 54 | * @param types The type scope being used to resolve the statement. 55 | * @return The converted DSR associated statement as a HIR associated statement 56 | */ 57 | private fun associatedStmt(stmt: DSRAssociatedStmt, values: Values, types: Types): AssociatedStmt { 58 | return when (stmt) { 59 | is DSRStmt.Function -> function(stmt, values, types, true) 60 | } 61 | } 62 | 63 | /** 64 | * @param stmt The DSR function being converted into HIR. 65 | * @param values The value scope used to resolve the statement. 66 | * @param types The type scope being used to resolve the statement. 67 | * @param associated If true, the generic parameter branch will be pushed with a depth of 1 rather than 0 to allow the use of the generic parameters 68 | * from implementations and traits. 69 | * @return The converted DSR function as a HIR function containing resolved names. 70 | */ 71 | private fun function(stmt: DSRStmt.Function, values: Values, types: Types, associated: Boolean): Stmt.Function { 72 | val indexSinceDecl = if (associated) 1 else 0 73 | val values = Values(stmt.parameterBranch, indexSinceDecl, values) 74 | val types = Types(stmt.genericParams?.branch ?: Branch(), indexSinceDecl, types) 75 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 76 | val params = stmt.parameters.map { param -> 77 | when (param) { 78 | is DSRFunctionParam.Pattern -> FunctionParam.Pattern(pattern(param.pattern, values, types), type(param.ast.type, types), param.ast) 79 | is DSRFunctionParam.Self -> FunctionParam.Self(param, param.ast.type?.let { type -> type(type, types) }) 80 | } 81 | } 82 | 83 | val block = stmt.block?.let { block -> block(block, values, types) } 84 | return Stmt.Function(stmt.genericParams, whereClause, params, block, stmt.ast) 85 | } 86 | 87 | 88 | /** 89 | * @param stmt The DSR implementation being converted into HIR. 90 | * @param values The value scope used to resolve the statement. 91 | * @param types The type scope being used to resolve the statement. 92 | * @return The converted DSR implementation as a HIR implementation containing resolved names. 93 | */ 94 | private fun implementation(stmt: DSRStmt.Implementation, values: Values, types: Types): Stmt { 95 | val values = Values(Branch(), 0, values) 96 | val types = Types(stmt.genericParams?.branch ?: Branch(), 0, types) 97 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 98 | val type = type(stmt.ast.type, types) 99 | val statements = stmt.statements.map { stmt -> associatedStmt(stmt, values, types) } 100 | 101 | if (stmt.ast.trait == null) return Stmt.InherentImpl(stmt.genericParams, whereClause, type, statements, stmt.ast) 102 | val trait = traitItem(stmt.ast.trait, types) 103 | return Stmt.TraitImpl(stmt.genericParams, whereClause, type, trait, statements, stmt.ast) 104 | } 105 | 106 | /** 107 | * @param stmt The DSR trait being converted into HIR. 108 | * @param values The value scope used to resolve the statement. 109 | * @param types The type scope being used to resolve the statement. 110 | * @return The converted DSR trait as a HIR trait containing resolved names. 111 | */ 112 | private fun trait(stmt: DSRStmt.Trait, values: Values, types: Types): Stmt.Trait { 113 | val values = Values(Branch(), 0, values) 114 | val types = Types(stmt.genericParams?.branch ?: Branch(), 0, types) 115 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 116 | val statements = stmt.statements.map { stmt -> associatedStmt(stmt, values, types) } 117 | return Stmt.Trait(stmt.genericParams, whereClause, statements, stmt.ast) 118 | } 119 | 120 | /** 121 | * @param stmt The DSR let statement being converted into HIR. 122 | * @param values The value scope used to resolve the statement. 123 | * @param types The type scope being used to resolve the statement. 124 | * @return The converted DSR let statement as a HIR let statement containing resolved names as well as the next value branch that should be used. 125 | */ 126 | private fun let(stmt: DSRStmt.Let, values: Values, types: Types): Pair { 127 | val newValues = Values(stmt.branch, values.indexSinceDecl + 1, values) 128 | val pattern = pattern(stmt.pattern, values, types) 129 | val type = stmt.ast.type?.let { type -> type(type, types) } 130 | val initializer = stmt.initializer?.let { init -> expr(init, values, types) } 131 | val hir = Stmt.Let(pattern, type, initializer, stmt.ast) 132 | 133 | return Pair(hir, newValues) 134 | } 135 | 136 | /** 137 | * @param stmt The DSR module converted into HIR. 138 | * @return The converted DSR module as a HIR module containing resolved names. 139 | */ 140 | private fun module(stmt: DSRStmt.Module): Stmt.Module { 141 | val values = Values(stmt.values, 0, null) 142 | val types = Types(stmt.types, 0, null) 143 | return Stmt.Module(stmt.statements.map { stmt -> stmt(stmt, values, types).first }) 144 | } 145 | 146 | /** 147 | * @param stmt The DSR struct converted into HIR. 148 | * @param types The type scope being used to resolve the statement. 149 | * @return The converted DSR struct as a HIR struct containing resolved names. 150 | */ 151 | private fun struct(stmt: DSRStmt.Struct, types: Types): Stmt.Struct { 152 | val types = Types(stmt.genericParams?.branch ?: Branch(), 0, types) 153 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 154 | val fields = stmt.ast.fields.map { (token, type) -> Pair(token, type(type, types)) } 155 | return Stmt.Struct(stmt.genericParams, whereClause, fields, stmt.ast) 156 | } 157 | 158 | /** 159 | * @param stmt The DSR tuple struct converted into HIR. 160 | * @param types The type scope being used to resolve the statement. 161 | * @return The converted DSR tuple struct as a HIR tuple struct containing resolved names. 162 | */ 163 | private fun tupleStruct(stmt: DSRStmt.TupleStruct, types: Types): Stmt.TupleStruct { 164 | val types = Types(stmt.genericParams?.branch ?: Branch(), 0, types) 165 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 166 | val fields = stmt.ast.fields.map { type -> type(type, types) } 167 | return Stmt.TupleStruct(stmt.genericParams, whereClause, fields, stmt.ast) 168 | } 169 | 170 | /** 171 | * @param stmt The DSR unit struct converted into HIR. 172 | * @param types The type scope being used to resolve the statement. 173 | * @return The converted DSR unit struct as a HIR unit struct containing resolved names. 174 | */ 175 | private fun unitStruct(stmt: DSRStmt.UnitStruct, types: Types): Stmt.UnitStruct { 176 | val types = Types(stmt.genericParams?.branch ?: Branch(), 0, types) 177 | val whereClause = whereClause(stmt.genericParams, stmt.ast.whereClause, types) 178 | return Stmt.UnitStruct(stmt.genericParams, whereClause, stmt.ast) 179 | } 180 | 181 | /** 182 | * @param genericParams The generic parameters that may contain type bounds included in the returned where clause. 183 | * @param whereClause The DSR where clause being converted into HIR. 184 | * @param types The type scope being used to resolve the statement. 185 | * @return The HIR where clause combining predicates in the generic parameters and the where clause. 186 | */ 187 | private fun whereClause(genericParams: DSRGenericParams?, whereClause: ASTWhereClause?, types: Types): WhereClause { 188 | val predicates = ArrayList>() 189 | genericParams?.let { generics -> 190 | val predicatesToAdd = generics.params 191 | .zip(generics.ast.params.map { param -> param.bounds }) 192 | .mapNotNull { (param, bounds) -> bounds?.let { Pair(Type.ADT(TypeItemRef.Normal(param, null)), typeParamBounds(bounds, types)) } } 193 | predicates.addAll(predicatesToAdd) 194 | } 195 | 196 | whereClause?.let { where -> 197 | val predicatesToAdd = where.clauseItems 198 | .map { clauseItem -> Pair(type(clauseItem.type, types), typeParamBounds(clauseItem.bounds, types)) } 199 | predicates.addAll(predicatesToAdd) 200 | } 201 | 202 | return WhereClause(predicates) 203 | } 204 | 205 | /** 206 | * @param type The AST type being converted into an HIR type. 207 | * @param types The type scope used to resolve the AST type. 208 | * @return The converted AST type as a HIR type. 209 | */ 210 | private fun type(type: ASTType, types: Types): Type { 211 | return when (type) { 212 | is ASTType.Error -> Type.Error 213 | is ASTType.Path -> typePath(type.path, types)?.let { item -> Type.ADT(item) } ?: Type.Error 214 | is ASTType.Tuple -> Type.Tuple(type.fields.map { field -> type(field, types) }) 215 | } 216 | } 217 | 218 | /** 219 | * @param bounds The AST type parameter bounds being converted into HIR. 220 | * @param types The type scope used to resolve the AST param bounds. 221 | * @return The converted AST type param bounds as HIR type param bounds. 222 | */ 223 | private fun typeParamBounds(bounds: ASTTypeParamBounds, types: Types): TypeParamBounds { 224 | val traits = bounds.bounds.map { path -> traitItem(path, types) }.filterNotNull() 225 | return TypeParamBounds(traits) 226 | } 227 | 228 | 229 | /** 230 | * @param path The normal complex path being resolved. 231 | * @param types The type scope used to resolve the path. 232 | * @param index The index in the path's body being converted into a TypeItemRef. 233 | * @return The converted type item reference or null if an error occurred 234 | */ 235 | private fun pathBody(body: List, types: Types, index: Int = body.size - 1): TypeItemRef? { 236 | val segment = body[index] 237 | val generics = segment.generics?.let { genericArgs(it, types) } 238 | 239 | if (index == 0) 240 | return getItem(segment.id, types, "scope")?.let { item -> TypeItemRef.Normal(item, generics) } 241 | 242 | val previous = pathBody(body, types, index - 1) ?: return null 243 | return associatedTypeIn(previous, segment.id, generics) 244 | } 245 | 246 | 247 | /** 248 | * @param path The complex path being interpreted as a type path. Can be normal or qualified 249 | * @param types The type scope used to resolve the path. 250 | * @return The type item reference if the item was found. 251 | */ 252 | private fun typePath(path: ComplexPath, types: Types): TypeItemRef? { 253 | return when (path) { 254 | is ComplexPath.Error -> null 255 | is ComplexPath.Normal -> typePath(path, types) 256 | is ComplexPath.Qualified -> qualifiedTypePath(path, types) 257 | } 258 | } 259 | 260 | /** 261 | * @param path The normal complex path being resolved. 262 | * @param types The type scope used to resolve the path. 263 | * @return The type item reference of the item if the item was found. 264 | */ 265 | private fun typePath(path: ComplexPath.Normal, types: Types) = pathBody(path.body, types) 266 | private fun qualifiedTypePath(path: ComplexPath.Qualified, types: Types): TypeItemRef.Qualified? { 267 | val type = type(path.type, types) 268 | val first = path.body.first() 269 | 270 | if (path.trait == null) { 271 | zinc.reportCompileError(CompilerError.useQualifiedPath(first.id, path.range())) 272 | return null 273 | } 274 | 275 | val trait = traitItem(path.trait, types) ?: return null 276 | 277 | val generics = first.generics?.let { generics -> genericArgs(generics, types) } 278 | 279 | if (path.body.size > 1) { 280 | zinc.reportCompileError(CompilerError.useQualifiedPath(path.body[1].id, path.range())) 281 | return null 282 | } 283 | 284 | return TypeItemRef.Qualified(type, trait, first.id, generics) 285 | } 286 | 287 | /** 288 | * @param path The complex path being interpreted as a value path. 289 | * @param values The value scope used to resolve the path. 290 | * @param types The type scope used to resolve the path. 291 | * @return The value item reference if the item was found. 292 | */ 293 | private fun valuePath(path: ComplexPath, values: Values, types: Types): ValueItemRef? { 294 | return when (path) { 295 | is ComplexPath.Error -> null 296 | is ComplexPath.Normal -> unqualifiedValuePath(path, values, types) 297 | is ComplexPath.Qualified -> qualifiedValuePath(path, values, types) 298 | } 299 | } 300 | 301 | private fun unqualifiedValuePath(path: ComplexPath.Normal, values: Values, types: Types): ValueItemRef? { 302 | val last = path.body.last() 303 | val generics = last.generics?.let { generics -> genericArgs(generics, types) } 304 | if (path.body.size == 1) { 305 | val item = getItem(last.id, values, "scope") ?: return null 306 | return ValueItemRef.Normal(item, generics) 307 | } 308 | 309 | val typeItem = pathBody(path.body, types, path.body.size - 2) ?: return null 310 | return associatedValueIn(typeItem, last.id, generics) 311 | } 312 | 313 | private fun qualifiedValuePath(path: ComplexPath.Qualified, values: Values, types: Types): ValueItemRef? { 314 | val type = type(path.type, types) 315 | val first = path.body.first() 316 | val firstGenerics = first.generics?.let { generics -> genericArgs(generics, types) } 317 | 318 | return when (path.body.size) { 319 | 1 -> if (path.trait == null) { 320 | ValueItemRef.TypeAccess(type, first.id, firstGenerics) 321 | } else { 322 | ValueItemRef.Qualified(type, traitItem(path.trait, types) ?: return null, first.id, firstGenerics) 323 | } 324 | 325 | 2 -> { 326 | val second = path.body[1] 327 | val secondGenerics = second.generics?.let { generics -> genericArgs(generics, types) } 328 | val trait = if (path.trait == null) { 329 | zinc.reportCompileError(CompilerError.useQualifiedPath(second.id, path.range())) 330 | return null 331 | } else traitItem(path.trait, types) ?: return null 332 | ValueItemRef.TypeAccess( 333 | Type.ADT(TypeItemRef.Qualified(type, trait, first.id, firstGenerics)), 334 | second.id, 335 | secondGenerics 336 | ) 337 | } 338 | 339 | else -> { 340 | val second = path.body[1] 341 | zinc.reportCompileError( 342 | CompilerError.useQualifiedPath( 343 | if (path.trait == null) first.id else second.id, 344 | path.range() 345 | ) 346 | ) 347 | null 348 | } 349 | } 350 | } 351 | 352 | /** 353 | * @param item The type item reference which [name] is being searched for in. 354 | * @param name The name of the associated type being searched for. 355 | * @param genericArgs The HIR generic args provided with the name. 356 | */ 357 | private fun associatedTypeIn(item: TypeItemRef, name: Token, genericArgs: GenericArgs?): TypeItemRef? { 358 | return when (item) { 359 | is TypeItemRef.Normal -> when (item.type) { 360 | is Generic, 361 | is Struct, 362 | is TupleStruct, 363 | is UnitStruct -> { 364 | zinc.reportCompileError( 365 | CompilerError.itemDoesNotHaveAssociatedItems( 366 | name, 367 | item.type.name() 368 | ) 369 | ) // TODO: possibly swap this for a qualified error 370 | null 371 | } 372 | 373 | is Module -> TypeItemRef.Normal(getItem(name, Types(item.type.types, 0, null), "module") ?: return null, genericArgs) 374 | is Trait -> TODO("add associated item look up to traits in the DSR") 375 | } 376 | 377 | is TypeItemRef.Qualified -> { // pretty sure its impossible but just in case 378 | zinc.reportCompileError( 379 | CompilerError.useQualifiedPath( 380 | name, 381 | name.asRange() 382 | ) 383 | ) 384 | null 385 | } 386 | } 387 | } 388 | 389 | /** 390 | * @param item The value item reference which [name] is being searched for in. 391 | * @param name The name of the associated value being searched for. 392 | * @param genericArgs The HIR generic args provided with the name. 393 | */ 394 | private fun associatedValueIn(item: TypeItemRef, name: Token, genericArgs: GenericArgs?): ValueItemRef? { 395 | return when (item) { 396 | is TypeItemRef.Normal -> when (item.type) { 397 | is Generic, 398 | is Struct, 399 | is TupleStruct, 400 | is UnitStruct -> ValueItemRef.TypeAccess(Type.ADT(item), name, genericArgs) 401 | 402 | is Module -> ValueItemRef.Normal(getItem(name, Values(item.type.values, 0, null), "module") ?: return null, genericArgs) 403 | is Trait -> TODO("add associated item look up to traits in the DSR") 404 | } 405 | 406 | is TypeItemRef.Qualified -> { // pretty sure its impossible but just in case 407 | zinc.reportCompileError( 408 | CompilerError.useQualifiedPath( 409 | name, 410 | name.asRange() 411 | ) 412 | ) 413 | null 414 | } 415 | } 416 | } 417 | 418 | /** 419 | * @param generics The AST generic arguments being converted into HIR. 420 | * @param types The type scope used to resolve the path. 421 | * @return The converted AST generic arguments as HIR generic arguments. 422 | */ 423 | private fun genericArgs(generics: ASTGenericArgs, types: Types) = GenericArgs(generics.types.map { type -> type(type, types) }) 424 | 425 | /** 426 | * @param path The complex path being interpreted as a type path. 427 | * @param types The type scope used to resolve the path. 428 | * @return A normal type item reference where the inner item must be a trait. TODO: enforce this with the type system 429 | * 430 | * A wrapper around [typePath] that makes sure the item referenced is a trait. 431 | */ 432 | private fun traitItem(path: ComplexPath, types: Types): TypeItemRef.Normal? { 433 | val item = typePath(path, types) ?: return null 434 | return when (item) { 435 | is TypeItemRef.Normal -> when (item.type) { 436 | is Trait -> item 437 | else -> { 438 | zinc.reportCompileError(CompilerError.expectedTrait(path.range(), item.type.name())) 439 | null 440 | } 441 | } 442 | 443 | else -> { 444 | zinc.reportCompileError(CompilerError.expectedTrait(path.range(), "qualified item")) 445 | null 446 | } 447 | } 448 | } 449 | 450 | /** 451 | * @param expr The DSR expression being converted into HIR. 452 | * @param values The value path used to resolve the expression. 453 | * @param types The type path used to resolve the expression. 454 | * @return The converted DSR expression as a HIR expression. 455 | */ 456 | private fun expr(expr: DSRExpr, values: Values, types: Types): Expr { 457 | return when (expr) { 458 | is DSRExpr.Binary -> Expr.Binary(expr(expr.left, values, types), expr(expr.right, values, types), expr.ast) 459 | is DSRExpr.Break -> breakExpr(expr, values, types) 460 | is DSRExpr.Call -> call(expr, values, types) 461 | is DSRExpr.Closure -> closure(expr, values, types) 462 | is DSRExpr.Continue -> continueExpr(expr) 463 | is DSRExpr.FieldGet -> Expr.FieldGet( 464 | expr(expr.callee, values, types), 465 | expr.ast.segment.id, 466 | expr.ast.segment.generics?.let { generics -> genericArgs(generics, types) }, 467 | expr.ast 468 | ) 469 | 470 | is DSRExpr.Group -> group(expr, values, types) 471 | is DSRExpr.Index -> Expr.Index(expr(expr.callee, values, types), expr.args.map { arg -> expr(arg, values, types) }, expr.ast) 472 | is DSRExpr.Block -> block(expr, values, types) 473 | is DSRExpr.For -> forExpr(expr, values, types) 474 | is DSRExpr.If -> ifExpr(expr, values, types) 475 | is DSRExpr.Loop -> loop(expr, values, types) 476 | is DSRExpr.While -> whileExpr(expr, values, types) 477 | is DSRExpr.Literal -> Expr.Literal(expr.ast) 478 | is DSRExpr.Match -> match(expr, values, types) 479 | is DSRExpr.Path -> Expr.Item(valuePath(expr.ast.path, values, types), expr.ast) 480 | is DSRExpr.Range -> Expr.Range( 481 | expr.left?.let { left -> expr(left, values, types) }, 482 | expr.right?.let { right -> expr(right, values, types) }, 483 | expr.ast 484 | ) 485 | 486 | is DSRExpr.Return -> returnExpr(expr, values, types) 487 | is DSRExpr.Unary -> Expr.Unary(expr(expr.right, values, types), expr.ast) 488 | } 489 | } 490 | 491 | /** 492 | * @param call The DSR call expression being converted into HIR. 493 | * @param values The value path used to resolve the expression. 494 | * @param types The type path used to resolve the expression. 495 | * @return A HIR call expression or a HIR method call expression if the callee of the expression was a field get expr. 496 | */ 497 | private fun call(call: DSRExpr.Call, values: Values, types: Types): Expr { 498 | return if (call.callee !is DSRExpr.FieldGet) 499 | Expr.Call(expr(call.callee, values, types), call.args.map { arg -> expr(arg, values, types) }, call.ast) 500 | else 501 | Expr.MethodCall( 502 | expr(call.callee.callee, values, types), 503 | call.callee.ast.segment.id, 504 | call.callee.ast.segment.generics?.let { generics -> genericArgs(generics, types) }, 505 | call.args.map { arg -> expr(arg, values, types) }, 506 | call.ast 507 | ) 508 | } 509 | 510 | private fun closure(closure: DSRExpr.Closure, values: Values, types: Types): Expr.Closure { 511 | // TODO: do not allow return statements inside of closures 512 | val patterns = closure.patterns.map { pattern -> pattern(pattern, values, types) } 513 | val expr = expr(closure.expr, Values(closure.paramScope, values.indexSinceDecl + 1, values), types) 514 | return Expr.Closure(patterns, expr, closure.ast) 515 | } 516 | 517 | private fun breakExpr(breakExpr: DSRExpr.Break, values: Values, types: Types): Expr.Break { 518 | val value = breakExpr.value?.let { value -> expr(value, values, types) } 519 | return Expr.Break(value, breakExpr.ast) 520 | } 521 | 522 | private fun continueExpr(continueExpr: DSRExpr.Continue): Expr.Continue { 523 | return Expr.Continue(continueExpr.ast) 524 | } 525 | 526 | private fun group(expr: DSRExpr.Group, values: Values, types: Types): Expr { 527 | return if (expr.exprs.size == 1) expr(expr.exprs.first(), values, types) 528 | else Expr.Tuple(expr.exprs.map { field -> expr(field, values, types) }, expr.ast) 529 | } 530 | 531 | private fun block(expr: DSRExpr.Block, values: Values, types: Types): Expr.Block { 532 | var values = Values(expr.values, values.indexSinceDecl + 1, values) 533 | val types = Types(expr.types, types.indexSinceDecl + 1, types) 534 | return Expr.Block(expr.stmts.map { stmt -> 535 | val (stmt, newValues) = stmt(stmt, values, types) 536 | values = newValues 537 | stmt 538 | }, expr.ast) 539 | } 540 | 541 | private fun forExpr(expr: DSRExpr.For, values: Values, types: Types): Expr.For { 542 | val pattern = pattern(expr.pattern, values, types) 543 | val iterator = expr(expr.iterator, values, types) 544 | val block = block(expr.block, values, types) 545 | return Expr.For(pattern, iterator, block, expr.ast) 546 | } 547 | 548 | private fun ifExpr(expr: DSRExpr.If, values: Values, types: Types): Expr.If { 549 | val condition = expr(expr.condition, values, types) 550 | val then = block(expr.then, values, types) 551 | val elseBranch = expr.orElse?.let { orElse -> expr(orElse, values, types) } 552 | return Expr.If(condition, then, elseBranch, expr.ast) 553 | } 554 | 555 | private fun loop(expr: DSRExpr.Loop, values: Values, types: Types): Expr.Loop { 556 | val block = block(expr.block, values, types) 557 | return Expr.Loop(block, expr.ast) 558 | } 559 | 560 | private fun whileExpr(expr: DSRExpr.While, values: Values, types: Types): Expr.While { 561 | val condition = expr(expr.condition, values, types) 562 | val block = block(expr.then, values, types) 563 | return Expr.While(condition, block, expr.ast) 564 | } 565 | 566 | private fun match(expr: DSRExpr.Match, values: Values, types: Types): Expr.Match { 567 | val exprToMatch = expr(expr.expr, values, types) 568 | val branches = expr.branches.map { (patternValuesBranch, pattern, expr) -> 569 | val branchValues = Values(patternValuesBranch, values.indexSinceDecl + 1, values) 570 | val pattern = pattern(pattern, values, types) 571 | val expr = expr(expr, branchValues, types) 572 | Pair(pattern, expr) 573 | } 574 | return Expr.Match(exprToMatch, branches, expr.ast) 575 | } 576 | 577 | private fun returnExpr(expr: DSRExpr.Return, values: Values, types: Types): Expr.Return { 578 | val returnValue = expr.value?.let { expr -> expr(expr, values, types) } 579 | return Expr.Return(returnValue, expr.ast) 580 | } 581 | 582 | /** 583 | * @param pattern The DSR pattern being converted into HIR. 584 | * @param values The value path used to resolve the expression. 585 | * @param types The type path used to resolve the expression. 586 | * @return The converted DSR pattern as a HIR pattern. 587 | */ 588 | private fun pattern(pattern: DSRPattern, values: Values, types: Types): Pattern { 589 | return when (pattern) { 590 | is DSRPattern.Literal -> Pattern.Literal(pattern.ast.token) 591 | is DSRPattern.Tuple -> Pattern.Tuple(pattern.fields.map { field -> pattern(field, values, types) }, pattern.ast) 592 | is DSRPattern.Variable -> Pattern.Variable(pattern.variable, pattern.ast) 593 | is DSRPattern.Wildcard -> Pattern.Wildcard(pattern.ast.token) 594 | } 595 | } 596 | 597 | /** 598 | * @param identifier The token being used to get an item from the scope. 599 | * @param branches The scope being used. 600 | * @param env The name of the environment the item is being grabbed from. For example, "scope", or "module" 601 | * @return The item found in the scope or null if the item is not found. 602 | * 603 | * Reports a name not found error if a name is not found. 604 | */ 605 | private fun getItem(identifier: Token, branches: BranchNode, env: String): T? { 606 | if (branches.branch.data.containsKey(identifier.lexeme!!)) { 607 | val item = branches.branch.data[identifier.lexeme] 608 | return item 609 | } 610 | zinc.reportCompileError(CompilerError.nameNotFound(identifier.lexeme, identifier.asRange(), env)) 611 | return null 612 | } 613 | } --------------------------------------------------------------------------------