Skip to content

Commit

Permalink
Removed operator overloading from the language
Browse files Browse the repository at this point in the history
  • Loading branch information
KCreate committed Mar 15, 2017
1 parent 818c231 commit 9c542c1
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 376 deletions.
32 changes: 32 additions & 0 deletions src/charly/interpreter/calculator.cr
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ module Charly

# Addition
def self.add(left : BaseType, right : BaseType)
if left.is_a? TArray
if right.is_a? TArray
return TArray.new left.value + right.value
else
new_array = left.value.dup
new_array << right
return TArray.new new_array
end
end

if left.is_a?(TNumeric) && right.is_a?(TNumeric)
return TNumeric.new(left.value + right.value)
end
Expand Down Expand Up @@ -202,6 +212,16 @@ module Charly
return TBoolean.new(left.value == right.value)
end

if left.is_a?(TArray) && right.is_a?(TArray)
if left.value.size != right.value.size
return TBoolean.new false
end

return TBoolean.new left.value.equals?(right.value) { |left, right|
eq(left, right).value
}
end

if left.is_a?(TBoolean) && right.is_a?(TBoolean)
return TBoolean.new(left.value == right.value)
end
Expand Down Expand Up @@ -243,6 +263,18 @@ module Charly
return TBoolean.new(left.value != right.value)
end

if left.is_a?(TArray) && right.is_a?(TArray)
if left.value.size != right.value.size
return TBoolean.new true
end

equal = left.value.equals?(right.value) { |left, right|
eq left, right
}

return TBoolean.new !equal
end

if left.is_a?(TBoolean) && right.is_a?(TBoolean)
return TBoolean.new(left.value != right.value)
end
Expand Down
137 changes: 9 additions & 128 deletions src/charly/interpreter/visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -343,108 +343,22 @@ module Charly
end

def visit_unary_expression(node : UnaryExpression, scope, context)
# Resolve the right side
operator = node.operator
right = visit_expression(node.right, scope, context)

# Checks if this operator is unary overrideable
if operator.unary_operator?
override_method_name = operator.unary_method_name

method = nil
if right.is_a?(DataType) && right.data.contains override_method_name
method = right.data.get(override_method_name, Flag::IGNORE_PARENT)
elsif right.is_a? TArray
method = get_primitive_method(right, override_method_name, scope, context)
end

if method.is_a? TFunc
# Create a fake call expression
callex = CallExpression.new(
MemberExpression.new(
node.right,
IdentifierLiteral.new("#{operator}").at(node.right)
).at(node.right),
ExpressionList.new([] of ASTNode).at(node.right)
).at(node)

return visit_function_call(method, callex, right, scope, context)
end
end

return Calculator.visit_unary node.operator, right
end

def visit_binary_expression(node : BinaryExpression, scope, context)
# Resolve the left side
operator = node.operator
left = visit_expression(node.left, scope, context)

if operator.regular_operator?
override_method_name = operator.regular_method_name

method = nil
if left.is_a?(DataType) && left.data.contains override_method_name
method = left.data.get(override_method_name, Flag::IGNORE_PARENT)
elsif left.is_a? TArray
method = get_primitive_method(left, override_method_name, scope, context)
end

if method.is_a? TFunc
# Create a fake call expression
callex = CallExpression.new(
MemberExpression.new(
node.left,
IdentifierLiteral.new("#{operator}").at(node.left)
).at(node.left),
ExpressionList.new([
node.right,
] of ASTNode).at(node.right)
).at(node)

return visit_function_call(method, callex, left, scope, context)
end
end

# No primitive method was found
right = visit_expression(node.right, scope, context)
return Calculator.visit operator, left, right
end

def visit_comparison_expression(node : ComparisonExpression, scope, context)
# Resolve the left side
operator = node.operator
left = visit_expression(node.left, scope, context)

if operator.regular_operator?
override_method_name = operator.regular_method_name

method = nil
if left.is_a?(DataType) && left.data.contains override_method_name
method = left.data.get(override_method_name, Flag::IGNORE_PARENT)
elsif left.is_a? TArray
method = get_primitive_method(left, override_method_name, scope, context)
end

if method.is_a? TFunc
# Create a fake call expression
callex = CallExpression.new(
MemberExpression.new(
node.left,
IdentifierLiteral.new("#{operator}").at(node.left)
).at(node.left),
ExpressionList.new([
node.right,
] of ASTNode).at(node.right)
).at(node)

return visit_function_call(method, callex, left, scope, context)
end
end

# No primitive method was found
right = visit_expression(node.right, scope, context)

return Calculator.visit operator, left, right
end

Expand Down Expand Up @@ -1043,50 +957,17 @@ module Charly

# The first statement to succeed causes the block to run
statement.values.children.each do |value|
override_method_name = OPERATOR_MAPPING[TokenType::Equal]
method = nil
if test.is_a?(DataType) && test.data.contains override_method_name
method = test.data.get(override_method_name, Flag::IGNORE_PARENT)
elsif test.is_a? TArray
method = get_primitive_method(test, override_method_name, scope, context)
end

if method.is_a? TFunc

# Create a fake call expression
callex = CallExpression.new(
MemberExpression.new(
node.test,
IdentifierLiteral.new(override_method_name).at(node.test)
).at(node.test),
ExpressionList.new([value] of ASTNode).at(node.test)
).at(node.test)
result = visit_function_call(method, callex, test, scope, context)
result = Calculator.truthyness(result)

if result
begin
yield_value = visit_block(statement.block, Scope.new(scope), context)
rescue e : BreakException
yield_value = TNull.new
end

break
value = visit_expression(value, scope, context)
result = Calculator.eq(test, value).value

if result
begin
yield_value = visit_block(statement.block, Scope.new(scope), context)
rescue e : BreakException
yield_value = TNull.new
end
else

# If the method wasn't redirected, we evaluate the value here
# This is for future compatibility with the array spread operator
value = visit_expression(value, scope, context)
if Calculator.eq(test, value).value
begin
yield_value = visit_block(statement.block, Scope.new(scope), context)
rescue e : BreakException
yield_value = TNull.new
end

break
end
break
end
end

Expand Down
15 changes: 0 additions & 15 deletions src/charly/syntax/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1029,21 +1029,6 @@ module Charly
when TokenType::Identifier
identifier = IdentifierLiteral.new(@token.value).at(@token.location)
advance
when .is_operator?
operator_token = @token.type
identifier = IdentifierLiteral.new(@token.type.regular_method_name).at(@token.location)
advance

# Check for overrideable unary operators
if_token TokenType::AtSign do
if operator_token.unary_operator?
identifier.name = operator_token.unary_method_name
identifier.at(identifier.location_start, @token.location)
advance
else
unexpected_token @token.type
end
end
end

arguments = IdentifierList.new([] of ASTNode)
Expand Down
54 changes: 0 additions & 54 deletions src/std/primitives/array.ch
Original file line number Diff line number Diff line change
Expand Up @@ -396,60 +396,6 @@ export = primitive class Array {
items
}

/*
* Returns a new array by concatenating self and the other array
* If the argument is not an array, it will be appended (non-mutating)
* */
func +(element) {

// Return a copy of the current array and append the item
if (typeof element ! "Array") {
let new = @copy()
new.push(element)
return new
}

// Create a copy and append each item of the other array
let new = @copy()
element.each(->(item) {
new.push(item)
})
return new
}

/*
* Returns true if this array is equal to another array or value
* */
func ==(other) {

const other_type = typeof other

if (other_type ! typeof self) {
return false
}

// Check the length
if (other.length() ! @length()) {
return false
}

// Iterate over the contents
let equal = true
other.each(func(e, i) {
if (equal) {
equal = e == self[i]
}
})
equal
}

/*
* Same as == but negated
* */
func !(other) {
!@__equal(other)
}

/*
* Returns a sorted copy of this array
*
Expand Down
Loading

0 comments on commit 9c542c1

Please sign in to comment.