Skip to content

Commit

Permalink
[SYNTAX] Support new-less construction
Browse files Browse the repository at this point in the history
  • Loading branch information
PeyTy committed Jun 28, 2024
1 parent b813476 commit fb52139
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 8 deletions.
18 changes: 16 additions & 2 deletions source/compiler/normalizer.hexa
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// The Hexa Compiler
// Copyright (C) 2021-2023 Oleh Petrenko
// Copyright (C) 2021-2024 Oleh Petrenko
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
Expand Down Expand Up @@ -377,6 +377,18 @@ class Normalizer {
case Call(expr, args, argNames):
// Constructor
switch expr {
case NodeTypeValue(t):
let v = Expression.Ident(parentNames.get(typer.parents.get(e)) ?? DataHelper.extractTypeName(t), null)
let a = []
for arg in args {
// TODO generate default arg values
a.push(nodeToExpression(arg))
}
return Expression.New(v, a, typer.types.get(e))
}
// Optimize `'String'.charCodeAt(0)`
if args.length == 1 { switch expr {
case Dot(expr, name): if name == 'charCodeAt' { switch expr {
Expand Down Expand Up @@ -636,6 +648,7 @@ class Normalizer {
let v = Expression.Ident(parentNames.get(typer.parents.get(e)) ?? DataHelper.extractTypeName(t), null)
let a = []
for arg in args {
// TODO generate default arg values
a.push(nodeToExpression(arg))
}
return Expression.New(v, a, typer.types.get(e))
Expand Down Expand Up @@ -1364,7 +1377,8 @@ class Normalizer {
// Expressions
case New(path, t, args, fields, values, _):
return Statement.Const(unique('temp'), nodeToExpression(e), typer.types.get(e))
// Create temporal variable to store constructed value
return Statement.Const(unique('temp'), nodeToExpression(e), typer.types.get(e))
// TODO just use `Expression.Call`, cause doesn't fills defaults etc
case Call(e, args, argNames):
Expand Down
65 changes: 59 additions & 6 deletions source/compiler/typer.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,14 @@ class Typer {
)
}

// TODO ensure in parser `new` has no return type
if name == 'new-TODO#' {
types.set(
field,
Type.Function(varTypes(vars), toType(t, field), variadic)
)
}

case Static(f): switch f {
case Function(name, expr, vars, rettype, _, variadic):
if let rettype = rettype {
Expand All @@ -710,7 +718,8 @@ class Typer {
// Instance method
case Function(name, expr, vars, rettype, _, variadic):
if name == 'new' {
type.constructor = type.fieldNames.length - 1
// TODO this is wrong
// type.constructor = type.fieldNames.length - 1
}

if external, expr != null {
Expand All @@ -727,6 +736,7 @@ class Typer {
allowSuper = (extend != null)

if not external {
let rettype = name == 'new'? t : rettype
fillFunction(field, expr, vars, rettype)
}

Expand Down Expand Up @@ -2039,10 +2049,12 @@ class Typer {
}

var variadic = false
var constructor = false
switch node {
// TODO `(variadic, ...)`
case Function(_, _, _, _, _, isVariadic):
case Function(name, _, _, _, _, isVariadic):
variadic = isVariadic
constructor = name == 'new'
// var x: [] = [] // TODO invalid!!!
if let params = project.mapFuncParams.get(node) as! [NodeType] {
for genericParam in params {
Expand All @@ -2059,7 +2071,7 @@ class Typer {
}

functionReturnsAType = ret
functionActuallyReturns = false
functionActuallyReturns = constructor

let atts = project.mapDecorators.get(node)

Expand Down Expand Up @@ -2534,7 +2546,7 @@ class Typer {
}

// Expressions return values
fun fillExpression(node Node) {
fun fillExpression(node Node, asValue Bool = true) {
switch node {
// Just `name`
case Ident(name, params):
Expand Down Expand Up @@ -2748,6 +2760,10 @@ class Typer {
if not allowSuper {
fail('Cannot access `super` here', node)
}

case NodeTypeValue(_):
fillExpression(e, false)

case _:
fillExpression(e)
}
Expand Down Expand Up @@ -2958,8 +2974,14 @@ class Typer {
switch e {
case Super:
fail('Cannot access `super` here', node)

case NodeTypeValue(_):
fillExpression(e, asValue: false)

case _:
fillExpression(e)
}
fillExpression(e)

switch types.get(e) as! Type {
case EnumInstance(type):
failNonFatal('Type `\(type.name)` is defined here', type.parent)
Expand Down Expand Up @@ -3002,6 +3024,9 @@ class Typer {
// `T` or `T<G>`
case NodeTypeValue(t): switch t {
case Type(name):
if asValue {
fail('Cannot use type `\(name)` as a value, use `\(name)()` to call constructor', node)
}
let subj = find(name)
if subj == null {
fail('Cannot find type with name `\(name)`', node)
Expand Down Expand Up @@ -3037,6 +3062,7 @@ class Typer {

// `new T {names: values} ()`
// TODO `new T () {names: values}`
// TODO remove
case New(path, t, el, names, values):
let type = toType(t, node)
let subj = find(DataHelper.extractTypeName(t))
Expand Down Expand Up @@ -3182,11 +3208,38 @@ class Typer {
case Call(e, el, elNames):
// TODO validate `elNames`
// JavaScript evaluates arguments first
var constructor Type? = null
switch e {
case Super:
if not allowSuper {
fail('Cannot access `super` here', node)
}

case NodeTypeValue(t):
// Constructor
// TODO handle `<T>`
let type = toType(t, e)
// TODO better idea
let subj = find(DataHelper.extractTypeName(t))
parents.set(node, subj)

switch type {
case ClassInstance(type):
if type.constructor == -1 {
fail('Cannot construct class without `new () {}` constructor', node)
}

switch type.parent {
case Class(t, extend, implement, f, external, kind):
constructor = types.get(f[type.constructor])
}

type.useless = false
case _:
// TODO
fail('Constructor may instantiate only classes', node)
}

case _:
fillExpression(e)
}
Expand Down Expand Up @@ -3230,7 +3283,7 @@ class Typer {
return types.get(node)
}

let eType = types.get(e) ?? obviousTyping(parents.get(e) ?? e)
let eType = constructor ?? types.get(e) ?? obviousTyping(parents.get(e) ?? e)

switch eType {
case Function(args, returns, variadic):
Expand Down

0 comments on commit fb52139

Please sign in to comment.