Remove support for constant receivers

This removes support for syntax such as `A::B` where `A` and `B` are
constants. Inko has not allowed defining nested types or constants in
types for a while, and this syntax was only used in a few places to
bootstrap the runtime. Removing support for this syntax simplifies both
the parser and compiler quite a bit.
parent 1102c455
Pipeline #108539384 failed with stages
in 6 minutes and 49 seconds
......@@ -7,14 +7,12 @@ module Inkoc
include Predicates
include Inspect
attr_reader :name, :location, :receiver
attr_reader :name, :location
# name - The name of the constant as a String.
# location - The SourceLocation of the constant.
# receiver - The object to search for the constant.
def initialize(name, receiver, location)
def initialize(name, location)
@name = name
@receiver = receiver
@location = location
end
......@@ -22,20 +20,6 @@ module Inkoc
true
end
def qualified_name
segments = []
source = self
while source
segments << source.name
source = source.receiver
end
segments
.reverse
.join(Config::MODULE_SEPARATOR)
end
def self_type?
name == Config::SELF_TYPE
end
......
......@@ -31,10 +31,6 @@ module Inkoc
@late_binding
end
def qualified_name
name.qualified_name
end
def visitor_method
case name.name
when Config::SELF_TYPE
......
......@@ -9,20 +9,13 @@ module Inkoc
end
def resolve(node, scope)
type = resolve_without_error(node, scope)
type = scope.lookup_type(node.name) || TypeSystem::Error.new
if type.error?
diagnostics.undefined_constant_error(node.qualified_name, node.location)
diagnostics.undefined_constant_error(node.name, node.location)
end
type
end
def resolve_without_error(node, scope)
source =
node.receiver ? resolve_without_error(node.receiver, scope) : scope
source.lookup_type(node.name) || TypeSystem::Error.new
end
end
end
......@@ -638,16 +638,7 @@ module Inkoc
# Foo
# Foo::Bar
def constant(start)
node = constant_from_token(start)
while @lexer.next_type_is?(:colon_colon)
skip_one
start = advance_and_expect!(:constant)
node = constant_from_token(start, node)
end
node
constant_from_token(start)
end
# Parses a reference to a module global.
......@@ -1276,7 +1267,7 @@ module Inkoc
# _INKOC.panic(error.to_string)
AST::Send.new(
Config::PANIC_MESSAGE,
AST::Constant.new(Config::RAW_INSTRUCTION_RECEIVER, nil, loc),
AST::Constant.new(Config::RAW_INSTRUCTION_RECEIVER, loc),
[],
[AST::Send.new(Config::TO_STRING_MESSAGE, arg, [], [], loc)],
loc
......@@ -1373,8 +1364,8 @@ module Inkoc
values
end
def constant_from_token(token, receiver = nil)
AST::Constant.new(token.value, receiver, token.location)
def constant_from_token(token)
AST::Constant.new(token.value, token.location)
end
def identifier_from_token(token, type_arguments = [])
......
......@@ -511,7 +511,7 @@ module Inkoc
unless type.object?
return diagnostics.reopen_invalid_object_error(
node.name.qualified_name,
node.name.name,
node.location
)
end
......
......@@ -60,7 +60,7 @@ module Inkoc
body = AST::Body.new(exprs, loc)
new_return_type = AST::TypeName
.new(AST::Constant.new(Config::SELF_TYPE, nil, loc), [], loc)
.new(AST::Constant.new(Config::SELF_TYPE, loc), [], loc)
AST::Method.new(
Config::NEW_MESSAGE,
......@@ -104,7 +104,7 @@ module Inkoc
body = AST::Body.new(exprs, loc)
new_return_type = AST::TypeName
.new(AST::Constant.new(Config::SELF_TYPE, nil, loc), [], loc)
.new(AST::Constant.new(Config::SELF_TYPE, loc), [], loc)
AST::Method.new(
Config::NEW_MESSAGE,
......@@ -125,10 +125,10 @@ module Inkoc
AST::Identifier.new('obj', loc),
AST::Send.new(
'set_object',
AST::Constant.new(Config::RAW_INSTRUCTION_RECEIVER, nil, loc),
AST::Constant.new(Config::RAW_INSTRUCTION_RECEIVER, loc),
[],
[
AST::Constant.new(Config::FALSE_CONST, nil, loc),
AST::Constant.new(Config::FALSE_CONST, loc),
AST::Self.new(loc)
],
loc
......
......@@ -243,17 +243,11 @@ module Inkoc
def on_constant(node, body)
name = node.name
loc = node.location
source =
if node.receiver
process_node(node.receiver, body)
else
get_self(body, loc)
end
source = get_self(body, loc)
if source.type.lookup_attribute(name).any?
get_attribute(source, name, body, loc)
elsif !node.receiver && @module.globals.defined?(name)
elsif @module.globals.defined?(name)
get_global(name, body, loc)
else
get_nil(body, loc)
......
......@@ -2,14 +2,16 @@
# every module implicitly. Because the prelude has not yet been imported we can
# only expose a few core types defined directly in the top-level object.
let Inko = _INKOC.get_toplevel
let Boolean = Inko::Boolean
let True = Inko::True
let False = Inko::False
let Nil = Inko::Nil
let Object = Inko::Object
let String = Inko::String
let Integer = Inko::Integer
let Float = Inko::Float
let Block = Inko::Block
let Array = Inko::Array
let ByteArray = Inko::ByteArray
let Boolean = _INKOC.get_boolean_prototype
let True = _INKOC.get_true
let False = _INKOC.get_false
let Nil = _INKOC.get_nil
let Object = _INKOC.get_object_prototype
let String = _INKOC.get_string_prototype
let Integer = _INKOC.get_integer_prototype
let Float = _INKOC.get_float_prototype
let Block = _INKOC.get_block_prototype
let Array = _INKOC.get_array_prototype
let ByteArray = _INKOC.get_byte_array_prototype
......@@ -35,23 +35,15 @@ object Constant {
# The source location of the constant.
@location: SourceLocation
# The receiver of the constant, if any.
@receiver: ?Constant
# The type arguments passed to the constant.
@type_arguments: Array!(Node)
# A boolean indicating if the constant is an optional type or not.
@optional: Boolean
def init(
name: String,
location: SourceLocation,
receiver: ?Constant = Nil
) {
def init(name: String, location: SourceLocation,) {
@name = name
@location = location
@receiver = receiver
@type_arguments = Array.new
@optional = False
}
......@@ -61,25 +53,10 @@ object Constant {
@name
}
# Returns the receiver of this constant.
def receiver -> ?Constant {
@receiver
}
# Returns the type arguments to use for initialising the constant.
def type_arguments -> Array!(Node) {
@type_arguments
}
# Returns `True` if this constant is optional.
def optional? -> Boolean {
@optional
}
# Marks this constant as optional.
def optional -> Boolean {
@optional = True
}
}
impl Node for Constant {
......
......@@ -855,17 +855,7 @@ object Parser {
}
def constant(token: Token) !! ParseError -> Constant {
let mut node = constant_from_token(token)
{ peek_token.type == 'colon_colon' }.while_true {
# Skip the ":"
next_token
node = constant_from_token(
token: try token_of_type('constant'),
receiver: node
)
}
let node = Constant.new(name: token.value, location: token.location)
(peek_token.type == 'type_args_open').if_true {
# Skip the "!("
......@@ -917,7 +907,7 @@ object Parser {
}
(token.type == 'constant').if_true {
return constant_from_token(token)
return Constant.new(name: token.value, location: token.location)
}
throw TokenError.new(token)
......@@ -1169,11 +1159,6 @@ object Parser {
Identifier.new(name: token.value, location: token.location)
}
def constant_from_token(token: Token, receiver: ?Constant = Nil) -> Constant {
Constant
.new(name: token.value, location: token.location, receiver: receiver)
}
def next_token_is_argument?(start_token: Token) -> Boolean {
let peeked = peek_token
......
......@@ -6,4 +6,4 @@
# contains data such as the methods defined in the module.
#
# Modules are permanent objects, and are never garbage collected.
let Module = Inko::Module
let Module = _INKOC.get_attribute(Inko, 'Module')
# Methods for `Trait` that should be available before defining other types.
# The object traits are instances of.
let Trait = Inko::Trait
let Trait = _INKOC.get_attribute(Inko, 'Trait')
# The name of the attribute that stores all the implemented traits.
let IMPLEMENTED_TRAITS_ATTRIBUTE = '@_implemented_traits'
......
......@@ -1180,23 +1180,15 @@ test.group('Parsing constants') do (g) {
let node = parse_as(input: 'Foo', type: Constant)
assert.equal(node.name, 'Foo')
assert.equal(node.receiver, Nil)
}
g.test('Parsing a constant with a receiver') {
let node = parse_as(input: 'A::B', type: Constant)
assert.equal(node.name, 'B')
assert.equal(node.receiver.name, 'A')
assert.equal(node.receiver.receiver, Nil)
assert.equal(node.location.column, 4)
assert.true(node.type_arguments.empty?)
}
g.test('Parsing a constant with type arguments') {
let node = parse_as(input: 'A::B!(C)', type: Constant)
let node = parse_as(input: 'A!(B)', type: Constant)
assert.equal(node.name, 'A')
assert.equal(node.type_arguments.length, 1)
assert.equal((node.type_arguments[0] as Constant).name, 'C')
assert.equal((node.type_arguments[0] as Constant).name, 'B')
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment