Example #1
0
func AssignToGlobalVariable(name string, value Value, lineno int) {
	log.Tracef("sym", "Assigning value %s to global variable %s", value.ToString(), name)
	if _, in := GlobalScope[name]; !in {
		log.UndeclaredVariable(lineno, name)
	}
	GlobalScope[name] = Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
}
Example #2
0
func AssignToScopedVariable(name string, value Value, lineno int) {
	log.Tracef("sym", "Assigning value %s to scope-local variable %s", value.ToString(), name)
	if _, in1 := Scope[name]; !in1 {
		if _, in2 := GlobalScope[name]; !in2 {
			log.UndeclaredVariable(lineno, name)
			Scope[name] = Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
		} else {
			GlobalScope[name] = Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
		}
	} else {
		Scope[name] = Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
	}
}
Example #3
0
func (ue UnaryExpression) Execute() interface{} {
	log.Tracef("ast", "Executing binary expression %s", ue.Op)

	// Execute the value
	value := ue.Value.Execute().(Value)

	// Switch on the operator
	switch ue.Op {
	case "!":
		return handleNot(value, ue.Line)
	}

	panic("Supplied a unary operator not supported")

}
Example #4
0
func GetVariable(varName string, lineno int) Value {
	log.Tracef("sym", "Getting variable %s", varName)
	return GetVariableGeneric(varName, varName, lineno)
}
Example #5
0
func (be *BinaryExpression) Execute() interface{} {
	log.Tracef("ast", "Executing binary expression %s", be.Op)

	// Execute the left side
	left := be.Lhs.Execute().(Value)

	// Error check the response from the left side
	if left.Type == VALUE_UNDEFINED && !left.Written {
		log.TypeViolation(be.Line)
		left.Type = VALUE_UNDEFINED
		return left
	}

	//
	if left.Type == VALUE_UNDEFINED {
		left.Type = VALUE_UNDEFINED
		return left
	}

	// Short circuit the right side
	var right Value
	leftBool := left.ToBoolean()
	if be.Op == "||" && leftBool.Value.(bool) {
		right = Value{Type: VALUE_BOOLEAN, Value: true, Line: left.LineNo(), Written: left.Written}
	} else if be.Op == "&&" && !leftBool.Value.(bool) {
		right = Value{Type: VALUE_BOOLEAN, Value: false, Line: left.LineNo(), Written: left.Written}
	} else {
		right = be.Rhs.Execute().(Value)
	}

	// Error check the right side now
	if right.Type == VALUE_UNDEFINED && !right.Written {
		log.TypeViolation(be.Line)
		left.Type = VALUE_UNDEFINED
		return left
	}

	// If one side is undefined and written, we just return undefined
	if right.Type == VALUE_UNDEFINED {
		left.Type = VALUE_UNDEFINED
		return left
	}

	// If the types are simply not the same and none are undefined, we report a type violation and return undefined
	// We also dont do this for && and || (truthy) operations b
	if (left.Type != right.Type) && (!opIsCoersive(be.Op)) {
		log.TypeViolation(be.Line)
		left.Type = VALUE_UNDEFINED
		return left
	}

	// Handle each operation separately
	switch be.Op {
	case "+":
		return handlePlus(left, right, be.Line)
	case "-":
		return handleMinus(left, right, be.Line)
	case "*":
		return handleMult(left, right, be.Line)
	case "/":
		return handleDivide(left, right, be.Line)
	case "==":
		return handleEquiv(left, right, be.Line)
	case "!=":
		return handleNequiv(left, right, be.Line)
	case "||":
		return handleOr(left, right, be.Line)
	case "&&":
		return handleAnd(left, right, be.Line)
	case ">":
		return handleGt(left, right, be.Line)
	case "<":
		return handleLt(left, right, be.Line)
	case ">=":
		return handleGte(left, right, be.Line)
	case "<=":
		return handleLte(left, right, be.Line)
	}

	// This should never be reached
	panic("You just supplied a binary operator we dont support")

}