예제 #1
0
파일: symbol_table.go 프로젝트: mhoc/msp
func AssignToScopedObjectKey(objectName string, keyName string, value Value, lineno int) {
	if _, in1 := Scope[objectName]; !in1 {
		if _, in2 := GlobalScope[objectName]; !in2 {
			// Not in either local or global
			log.UndeclaredVariable(lineno, objectName)
			return
		} else {
			// In global
			gObject := GetVariable(objectName, lineno)
			if gObject.Type != VALUE_OBJECT {
				log.TypeViolation(lineno)
				return
			}
			if value.Type == VALUE_OBJECT || value.Type == VALUE_ARRAY {
				log.TypeViolation(lineno)
				return
			}
			gObject.Value.(map[string]Value)[keyName] =
				Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
		}
	} else {
		lObject := GetVariable(objectName, lineno)
		if lObject.Type != VALUE_OBJECT {
			log.TypeViolation(lineno)
			return
		}
		if value.Type == VALUE_OBJECT || value.Type == VALUE_ARRAY {
			log.TypeViolation(lineno)
			return
		}
		lObject.Value.(map[string]Value)[keyName] =
			Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
	}
}
예제 #2
0
파일: symbol_table.go 프로젝트: mhoc/msp
func AssignToScopedArrayIndex(arrayName string, indexNo int, value Value, lineno int) {

	if _, in1 := Scope[arrayName]; !in1 {
		if _, in2 := GlobalScope[arrayName]; !in2 {
			log.UndeclaredVariable(lineno, arrayName)
			return
		} else {
			gArray := GetVariable(arrayName, lineno)
			if gArray.Type != VALUE_ARRAY {
				log.TypeViolation(lineno)
				return
			}
			if value.Type == VALUE_OBJECT || value.Type == VALUE_ARRAY {
				log.TypeViolation(lineno)
				return
			}
			gArray.Value.(map[string]Value)[strconv.Itoa(indexNo)] =
				Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
		}
	} else {
		lArray := GetVariable(arrayName, lineno)
		if lArray.Type != VALUE_ARRAY {
			log.TypeViolation(lineno)
			return
		}
		if value.Type == VALUE_ARRAY || value.Type == VALUE_OBJECT {
			log.TypeViolation(lineno)
			return
		}
		lArray.Value.(map[string]Value)[strconv.Itoa(indexNo)] =
			Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
	}
}
예제 #3
0
func handlePlus(left Value, right Value, line int) Value {

	// Integers
	if left.Type == VALUE_INT && right.Type == VALUE_INT {
		left.Value = left.Value.(int) + right.Value.(int)
		return left
	}

	// Strings
	if left.Type == VALUE_STRING && right.Type == VALUE_STRING {
		lStr := left.Value.(string)
		rStr := right.Value.(string)
		if strings.Contains(lStr, "<br />") || strings.Contains(rStr, "<br />") {
			log.TypeViolation(line)
			left.Type = VALUE_UNDEFINED
			return left
		}
		left.Value = left.Value.(string) + right.Value.(string)
		return left
	}

	log.TypeViolation(line)
	left.Type = VALUE_UNDEFINED
	return left

}
예제 #4
0
func handleNot(v Value, line int) Value {

	if v.Type == VALUE_BOOLEAN {
		v.Value = !v.Value.(bool)
		return v
	}

	if v.Type == VALUE_INT {
		if v.Value.(int) == 0 {
			v.Type = VALUE_BOOLEAN
			v.Value = true
		} else {
			v.Type = VALUE_BOOLEAN
			v.Value = false
		}
		return v
	}

	if v.Type == VALUE_STRING {
		if len(v.Value.(string)) == 0 {
			v.Type = VALUE_BOOLEAN
			v.Value = true
		} else {
			v.Type = VALUE_BOOLEAN
			v.Value = false
		}
		return v
	}

	log.TypeViolation(line)
	v.Type = VALUE_UNDEFINED
	return v

}
예제 #5
0
파일: variables.go 프로젝트: mhoc/msp
func (a Assignment) Execute() interface{} {
	rhsResult := a.Rhs.Execute()

	// The type of the right side should always be a Value
	// This line is included just to throw an error if it ever isn't, which is
	// mainly for debugging
	rightValue := rhsResult.(Value)

	switch a.Type {
	case VAR_NORM:
		AssignToVariable(a.Name, rightValue, a.Line)
	case VAR_OBJECT:
		AssignToObjectKey(a.Name, a.ObjChild, rightValue, a.Line)
	case VAR_ARRAY:
		// Check to ensure the index is an int: otherwise type error
		index := a.Index.Execute().(Value)
		if index.Type != VALUE_INT {
			log.TypeViolation(a.Line)
			return nil
		}
		AssignToArrayIndex(a.Name, index.Value.(int), rightValue, a.Line)
	}

	return nil
}
예제 #6
0
func handleOr(left Value, right Value, line int) Value {

	// Convert the type of the left and right side if they arent boolean
	if left.Type == VALUE_INT {
		left.Type = VALUE_BOOLEAN
		left.Value = left.Value.(int) > 0
	}
	if right.Type == VALUE_INT {
		right.Type = VALUE_BOOLEAN
		right.Value = right.Value.(int) > 0
	}
	if left.Type == VALUE_STRING {
		left.Type = VALUE_BOOLEAN
		left.Value = len(left.Value.(string)) > 0
	}
	if right.Type == VALUE_STRING {
		right.Type = VALUE_BOOLEAN
		right.Value = len(right.Value.(string)) > 0
	}

	// Booleans
	if left.Type == VALUE_BOOLEAN && right.Type == VALUE_BOOLEAN {
		left.Value = left.Value.(bool) || right.Value.(bool)
		return left
	}

	log.TypeViolation(line)
	left.Type = VALUE_UNDEFINED
	return left

}
예제 #7
0
func handleNequiv(left Value, right Value, line int) Value {

	// Integers
	if left.Type == VALUE_INT && right.Type == VALUE_INT {
		left.Type = VALUE_BOOLEAN
		left.Value = left.Value.(int) != right.Value.(int)
		return left
	}

	// Booleans
	if left.Type == VALUE_BOOLEAN && right.Type == VALUE_BOOLEAN {
		left.Value = left.Value.(bool) != right.Value.(bool)
		return left
	}

	// Strings
	if left.Type == VALUE_STRING && right.Type == VALUE_STRING {
		left.Type = VALUE_BOOLEAN
		left.Value = left.Value.(string) != right.Value.(string)
		return left
	}

	log.TypeViolation(line)
	left.Type = VALUE_UNDEFINED
	return left

}
예제 #8
0
파일: builtins.go 프로젝트: mhoc/msp
func DocumentWrite(fc FunctionCall) interface{} {
	for _, arg := range fc.Args {
		argv := arg.Execute().(Value)
		fmt.Print(argv.ToString())
		switch argv.Type {
		case VALUE_OBJECT:
			if !log.EXTENSIONS {
				log.TypeViolation(fc.LineNo())
			}
		case VALUE_ARRAY:
			if !log.EXTENSIONS {
				log.TypeViolation(fc.LineNo())
			}
		}
	}
	return nil
}
예제 #9
0
파일: functions.go 프로젝트: mhoc/msp
func (f FunctionCall) Execute() interface{} {
	log.Trace("ast", "Executing function "+f.Name)

	// Create the local stack and return val
	f.LocalScope = make(map[string]Value)
	f.ReturnVal = Value{Type: VALUE_UNDEFINED, Line: f.Line}
	// Retrieve the function definition
	funVal := GetVariable(f.Name, f.Line)
	if funVal.Type != VALUE_FUNCTION {
		log.TypeViolation(f.Line)
		return f.ReturnVal
	}
	funDef := funVal.Value.(FunctionDef)
	// Check number of arguments
	if !funDef.ArbitraryArgs && len(f.Args) != len(funDef.ArgNames) {
		log.TypeViolation(f.Line)
		return f.ReturnVal
	}
	if funDef.ExecMiniscript {
		// Load the arguments into the local stack
		for i, name := range funDef.ArgNames {
			f.LocalScope[name] = f.Args[i].Execute().(Value)
		}
		// Save the old scope and set this local as its own scope
		oldScope := Scope
		Scope = f.LocalScope
		// Execute the function
		retVal := funDef.MSBody.Execute()
		var nRetVal Value
		switch retVal.(type) {
		case Return:
			nRetVal = retVal.(Return).Value.Execute().(Value)
		case Value:
			nRetVal = retVal.(Value)
		}
		// Restore the old scope
		Scope = oldScope
		return nRetVal
	} else {
		funDef.GoBody(f)
		return nil
	}
}
예제 #10
0
파일: symbol_table.go 프로젝트: mhoc/msp
func AssignToGlobalObjectKey(objectName string, keyName string, value Value, lineno int) {
	if _, in := GlobalScope[objectName]; !in {
		log.UndeclaredVariable(lineno, objectName)
	}

	// Get the object from the symbol table
	object := GetVariable(objectName, lineno)
	if object.Type != VALUE_OBJECT {
		log.TypeViolation(lineno)
		return
	}

	// If we are assigning an object or array, fail
	if value.Type == VALUE_OBJECT || value.Type == VALUE_ARRAY {
		log.TypeViolation(lineno)
		return
	}

	object.Value.(map[string]Value)[keyName] =
		Value{Type: value.Type, Value: value.Value, Line: value.Line, Written: true}
}
예제 #11
0
func handleDivide(left Value, right Value, line int) Value {

	// Integers
	if left.Type == VALUE_INT && right.Type == VALUE_INT {
		left.Value = left.Value.(int) / right.Value.(int)
		return left
	}

	log.TypeViolation(line)
	left.Type = VALUE_UNDEFINED
	return left

}
예제 #12
0
파일: assert.go 프로젝트: mhoc/msp
func (a Assert) Execute() interface{} {
	// Execute the value
	result := a.Value.Execute()
	// If its not a value, type error
	switch result.(type) {
	case Value:
	default:
		log.TypeViolation(a.Line)
	}
	// Evalute the value to a boolean
	bVal := result.(Value).ToBoolean()
	// Exit the program if it evaluates to false
	if !bVal.Value.(bool) {
		os.Exit(1)
	}
	return nil
}
예제 #13
0
파일: variables.go 프로젝트: mhoc/msp
func (vr Reference) Execute() interface{} {
	switch vr.Type {
	case VAR_NORM:
		return GetVariable(vr.Name, vr.LineNo())
	case VAR_OBJECT:
		return GetObjectMember(vr.Name, vr.ObjChild, vr.LineNo())
	case VAR_ARRAY:
		// Check to ensure the index is an int: otherwise type error
		index := vr.Index.Execute().(Value)
		if index.Type != VALUE_INT {
			log.TypeViolation(vr.Line)
			return Value{Type: VALUE_UNDEFINED, Line: vr.Line}
		}
		return GetArrayMember(vr.Name, index.Value.(int), vr.LineNo())
	default:
		panic("Bad variable reference type")
	}
	return nil
}
예제 #14
0
파일: symbol_table.go 프로젝트: mhoc/msp
func GetArrayMember(arrayName string, index int, lineno int) Value {

	// Find the array itself
	array := GetVariable(arrayName, lineno)
	if array.Type == VALUE_UNDEFINED {
		log.ValueError(lineno, arrayName)
	}
	if array.Type != VALUE_ARRAY {
		log.TypeViolation(lineno)
		return Value{Type: VALUE_UNDEFINED, Line: lineno}
	}

	oldScope := Scope
	Scope = array.Value.(map[string]Value)
	keyValue := GetVariableGeneric(strconv.Itoa(index), fmt.Sprintf("%s[%d]", arrayName, index), lineno)
	Scope = oldScope

	return Value{Type: keyValue.Type, Value: keyValue.Value, Written: keyValue.Written, Line: keyValue.Line}

}
예제 #15
0
파일: symbol_table.go 프로젝트: mhoc/msp
func GetObjectMember(objectName string, keyName string, lineno int) Value {

	// Find the object itself
	object := GetVariable(objectName, lineno)
	if object.Type == VALUE_UNDEFINED {
		log.ValueError(lineno, objectName)
	}
	if object.Type != VALUE_OBJECT {
		log.TypeViolation(lineno)
		return Value{Type: VALUE_UNDEFINED, Line: lineno}
	}

	// Set this object's fields as the new scope then restore it later
	// This is, quite possibly, the smartest thing I have ever devised. Lol. Lol. Lol.
	// Full of himself meter = 10/10. Chance of anyone ever seeing this: 1/10
	oldScope := Scope
	Scope = object.Value.(map[string]Value)
	keyValue := GetVariableGeneric(keyName, objectName+"."+keyName, lineno)
	Scope = oldScope

	// All other error handling is done in gvg()
	return Value{Type: keyValue.Type, Value: keyValue.Value, Written: keyValue.Written, Line: keyValue.Line}

}
예제 #16
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")

}