Beispiel #1
0
func ancestralFuncStub(pkg *tp.Package, fun *tp.Function) *string {
	foundAncestor := false

	name := null.GetString(fun.Name)
	args := ""
	for _, arg := range fun.Args {
		argType := null.GetInt32(arg.TypeId)
		ancestralArgType := FindAncestralType(pkg, argType)

		if ancestralArgType != -1 {
			foundAncestor = true
			argType = ancestralArgType
		}

		argTypeString := pkg.GetTypeName(argType)

		argName := argTypeString
		argName = argName + " %" + null.GetString(arg.Name)
		args = args + ", " + argName
	}
	if len(args) > 1 {
		args = args[2:]
	}

	returnType := null.GetInt32(fun.ReturnTypeId)
	ancestralReturnType := FindAncestralType(pkg, returnType)

	if ancestralReturnType != -1 {
		foundAncestor = true
		returnType = ancestralReturnType
	}

	returnTypeString := pkg.GetTypeName(returnType)
	returnVal := name + "(" + args + ") " + returnTypeString + " "

	opensType := null.GetInt32(fun.OpensTypeId)
	ancestralOpensType := FindAncestralType(pkg, opensType)

	if ancestralOpensType != -1 {
		foundAncestor = true
		opensType = ancestralOpensType
	}

	opensTypeString := pkg.GetTypeName(opensType)

	if opensTypeString != "Base" {
		returnVal = returnVal + opensTypeString
	}

	if foundAncestor {
		return &returnVal
	}
	return nil

}
Beispiel #2
0
func getBody(name string, fun *tp.Function) (body string) {
	var start int
	var end int
	depth := 0

	if fun.Instruction != nil {
		if len(fun.Instruction.Children) > 0 {
			for _, instruction := range fun.Instruction.Children {
				if *instruction.Type != constants.Instruction_TEXT {
					start = int(null.GetInt32(instruction.LineNumber))
					break
				}
			}

			done := false
			thisInstruction := fun.Instruction.Children[len(fun.Instruction.Children)-1]

			for !done {
				if len(thisInstruction.Children) > 0 {
					thisInstruction = thisInstruction.Children[len(thisInstruction.Children)-1]
					depth += 1
				} else {
					done = true
					end = int(null.GetInt32(thisInstruction.LineNumber))
				}
			}

		} else {
			return ""
		}
	} else {
		return "  [native function]"
	}

	data, err := ioutil.ReadFile("packages/" + name + "/functions.ts")
	if err != nil {
		panic("Couldnt find functions file for " + name)
	}

	lines := strings.Split(string(data), "\n")
	body = strings.Join(lines[start-1:end+depth], "\n")

	return
}
Beispiel #3
0
func FindAncestralType(pkg *tp.Package, thisType int32) int32 {
	someType := pkg.Types[thisType]

	implements := null.GetInt32(someType.Implements)
	if implements != 0 {
		return implements
	}

	return -1
}
Beispiel #4
0
func Process(pkg *tp.Package) string {
	for tindex, ttype := range pkg.Types {
		ttypeString := null.GetString(ttype.Name)
		println()
		for _, fun := range pkg.Functions {
			if tindex == int(null.GetInt32(fun.ScopeTypeId)) {
				println(ttypeString + "." + FuncStub(pkg, fun))
			}
		}
	}
	return ""
}
Beispiel #5
0
// TODO(SJ) : This should really return a list of descendants
func (pkg *Package) FindDescendantType(thisType int32) int {
	for index, someType := range pkg.Types {
		implements := null.GetInt32(someType.Implements)
		if implements == thisType && implements != 0 {
			// The implements field defaults to 0. Base doesn't implement Base. Text doesn't implement Base
			// TODO(SJ): make the default value -1 so I know if its not set versus something is inheriting from base
			// pkg.Log.Info("=== %v is ancestor of %v === (%v is of type %v and implements : %v)\n", thisType, someType, null.GetString(someType.Name), index, implements)
			// println("CHECK:", someType.GetName(), "implements", pkg.GetTypeName(someType.GetImplements()))
			return index
		}
	}
	return -1
}
Beispiel #6
0
func (ctx *LinkingContext) link(objId, scopeType int) {
	obj := ctx.Objects[objId]
	if null.GetBool(obj.Linked) == false {
		obj.ScopeTypeId = proto.Int(scopeType)
		obj.Linked = proto.Bool(true)
		path := obj.GetName()
		ctx.files = append(ctx.files, path)
		ctx.ProcessInstruction(obj.Root, scopeType, path)
		ctx.files = ctx.files[:(len(ctx.files) - 1)]
	} else {
		if scopeType != int(null.GetInt32(obj.ScopeTypeId)) {
			ctx.error("script", "Imported a script in two different scopes! Not processing second import.")
		}
	}
}
Beispiel #7
0
func ShortFuncStub(pkg *tp.Package, fun *tp.Function) string {
	name := null.GetString(fun.Name)
	args := ""
	for _, arg := range fun.Args {
		t := pkg.Types[int(null.GetInt32(arg.TypeId))]
		argName := null.GetString(t.Name)
		argName = argName
		args = args + ", " + argName
	}
	if len(args) > 1 {
		args = args[2:]
	}
	returnVal := name + "(" + args + ")"
	return returnVal
}
Beispiel #8
0
func (f *Function) BaseSignature(pkg2 protoface.Package) string {
	pkg := pkg2.(*Package)
	args := "("
	for i, arg := range f.Args {
		argName := null.GetString(arg.TypeString)
		if argName == "" {
			t := pkg.Types[int(null.GetInt32(arg.TypeId))]
			argName = null.GetString(t.Name)
		}
		if i != 0 {
			args += ","
		}
		args += argName
	}
	return fmt.Sprintf("%s.%s%s)", pkg.GetTypeName(f.GetScopeTypeId()), f.GetName(), args)
}
Beispiel #9
0
func (f *Function) Stub(pkg2 protoface.Package) string {
	pkg := pkg2.(*Package)
	ns := f.GetNamespace()
	if len(ns) == 0 {
		ns = "tritium"
	}
	fname := fmt.Sprintf("%s.%s", ns, f.GetName())
	args := ""
	for _, arg := range f.Args {
		argName := null.GetString(arg.TypeString)
		if argName == "" {
			t := pkg.Types[int(null.GetInt32(arg.TypeId))]
			argName = null.GetString(t.Name)
		}
		args = args + "," + argName
	}
	return fname + args
}
Beispiel #10
0
func (fun *Function) DebugInfo(pkg2 protoface.Package) string {
	pkg := pkg2.(*Package)
	name := fun.NameString()
	scopeType := fun.ScopeTypeString(pkg)
	returnType := fun.ReturnTypeString(pkg)
	openType := fun.OpensTypeString(pkg)

	args := ""
	for _, arg := range fun.Args {
		argName := null.GetString(arg.TypeString)
		if argName == "" {
			argName = pkg.GetTypeName(null.GetInt32(arg.TypeId))
		}
		args = args + "," + argName
	}

	return "@func " + scopeType + "." + name + "(" + args + ") " + returnType + " " + openType
}
Beispiel #11
0
func FuncStub(pkg *tp.Package, fun *tp.Function) string {
	name := null.GetString(fun.Name)
	args := ""
	for _, arg := range fun.Args {
		t := pkg.Types[int(null.GetInt32(arg.TypeId))]
		argName := null.GetString(t.Name)
		argName = argName + " %" + null.GetString(arg.Name)
		args = args + ", " + argName
	}
	if len(args) > 1 {
		args = args[2:]
	}
	returnVal := name + "(" + args + ") " + fun.ReturnTypeString(pkg) + " "
	opens := fun.OpensTypeString(pkg)
	if opens != "Base" {
		returnVal = returnVal + opens
	}
	return returnVal
}
Beispiel #12
0
func (ctx *LinkingContext) ProcessInstructionWithLocalScope(ins *tp.Instruction, scopeType int, localScope LocalDef, caller string, path string, justRoot bool) (returnType int) {
	returnType = -1
	ins.IsValid = proto.Bool(true)
	switch *ins.Type {
	case constants.Instruction_IMPORT:
		importLocation := ins.GetValue()

		// keep track of which files we're inside of, to detect circular imports
		val, present := ctx.Visiting[importLocation]
		if present && val {
			ctx.error(ins, "Circular import detected: %s", importLocation)
			panic(fmt.Sprintf("Circular import detected: %s", importLocation))
		}
		ctx.Visiting[importLocation] = true

		importId, ok := ctx.objMap[importLocation]
		if ok != true {
			ctx.error(ins, "Invalid import `%s`", ins.String())
		}
		// if we're linking the whole tree, then recurse
		if !justRoot {
			// Make sure this object is linked with the right scopeType
			ctx.link(importId, scopeType)

			// otherwise just set the script object's scope type
		} else {
			ctx.Objects[importId].ScopeTypeId = proto.Int(scopeType)
		}

		// pop the import stack (for circular import detection)
		ctx.Visiting[importLocation] = false

		ins.ObjectId = proto.Int(importId)
		ins.Value = nil
	case constants.Instruction_LOCAL_VAR:
		name := null.GetString(ins.Value)
		if name == "1" || name == "2" || name == "3" || name == "4" || name == "5" || name == "6" || name == "7" {
			if len(ins.Arguments) > 0 {
				// We are going to assign something to this variable
				returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path, justRoot)
				if returnType != ctx.textType {
					ctx.error(ins, "Numeric local vars can ONLY be Text")
				}
			}
			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, ctx.textType, localScope, caller, path, justRoot)
				}
			}
			returnType = ctx.textType
		} else { // Not numeric.
			typeId, found := localScope[name]
			if found {
				returnType = typeId
				if len(ins.Arguments) > 0 {
					ctx.error(ins, "The local variable \"%%%s\" has been assigned before and cannot be reassigned! Open a scope on it if you need to alter the contents.", name)
				} else {
					if ins.Children != nil {
						for _, child := range ins.Children {
							returnType = ctx.ProcessInstructionWithLocalScope(child, typeId, localScope, caller, path, justRoot)
						}
					}
				}

			} else {
				if len(ins.Arguments) > 0 {
					// We are going to assign something to this variable
					// But first, check for possible mutation and prevent it for now.
					if ins.Children != nil {
						ctx.error(ins, "May not open a scope during initialization of local variable \"%%%s\".", name)
					}
					returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path, justRoot)
					localScope[name] = returnType
				} else {
					ctx.error(ins, "I've never seen the variable \"%%%s\" before! Please assign a value before usage.", name)
				}
			}
		}

	case constants.Instruction_FUNCTION_CALL:
		stub := null.GetString(ins.Value)
		if stub == "yield" {
			ins.YieldTypeId = proto.Int32(int32(scopeType))
		}
		namespaces := ins.Namespaces()
		// ins.Namespace = nil // need to figure out where to do this step
		// process the args
		if ins.Arguments != nil {
			for _, arg := range ins.Arguments {
				argReturn := ctx.ProcessInstructionWithLocalScope(arg, scopeType, localScope, caller, path, justRoot)
				if argReturn == -1 {
					ctx.error(ins, "Invalid argument object %q", arg.String())
					return
				}
				stub = stub + "," + ctx.types[argReturn]
			}
		}
		// for each namespace specified by the user, look up the function wrt the current context type + function name
		var funcId int
		var ok bool
		for _, ns := range namespaces {
			funcId, ok = ctx.funList[scopeType][ns+"."+stub]
			if ok {
				break
			}
		}

		if !ok {
			readableCalleeStub := readableStub(stub)
			readableCallerStub := readableStub(caller)

			location := ""
			if len(path) > 0 {
				location = path
			} else {
				location = "Package " + ctx.Pkg.GetName()
			}

			msg := fmt.Sprintf("%s:%d: function %s.%s does not exist in namespace %s", location, ins.GetLineNumber(), ctx.types[scopeType], readableCalleeStub, namespaces[0])
			for i := 1; i < len(namespaces)-1; i++ {
				msg += ", " + namespaces[i]
			}
			if len(namespaces) > 1 {
				msg += " or " + namespaces[len(namespaces)-1]
			}
			msg += fmt.Sprintf("; (called from %s.%s).", ctx.types[scopeType], readableCallerStub)

			ctx.error(ins, msg)

			// message := fmt.Sprintf("Available functions in %s.%s:\n", ns, ctx.types[scopeType])
			// ns := strings.SplitN(stub, ".", 2)[0]
			// nsPrefix := ns + "."
			// for funcName, _ := range ctx.funList[scopeType] {
			// 	if strings.HasPrefix(funcName, nsPrefix) {
			// 		message += "\t" + nsPrefix + readableStub(funcName) + "\n"
			// 	}
			// }
			// log.Printf("%s\n", message)

			// ctx.error(ins, "%s:%d: could not find function %s.%s.%s (called from %s.%s.%s)", location, ins.GetLineNumber(), ns, ctx.types[scopeType], readableCalleeStub, callerNamespace, ctx.types[scopeType], readableCallerStub)

		} else {
			ins.FunctionId = proto.Int32(int32(funcId))
			fun := ctx.Pkg.Functions[funcId]
			returnType = int(null.GetInt32(fun.ReturnTypeId))
			opensScopeType := int(null.GetInt32(fun.OpensTypeId))
			if opensScopeType == 0 {
				// If we're a Base scope, don't mess with texas!
				opensScopeType = scopeType
			}
			// If it inherits:
			inheritedOpensScopeType := ctx.Pkg.FindDescendantType(int32(opensScopeType))
			if inheritedOpensScopeType != -1 {
				opensScopeType = inheritedOpensScopeType
			}

			// Copy the local scope
			parentScope := localScope
			localScope = make(LocalDef, len(parentScope))
			for s, t := range parentScope {
				localScope[s] = t
			}

			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, opensScopeType, localScope, stub, path, justRoot) // thread the name of the caller through the linkages
				}
			}
		}
	case constants.Instruction_TEXT:
		returnType = ctx.textType
	case constants.Instruction_BLOCK:
		if ins.Children != nil {
			for _, child := range ins.Children {
				returnType = ctx.ProcessInstructionWithLocalScope(child, scopeType, localScope, caller, path, justRoot)
			}
		}
	}
	return
}
Beispiel #13
0
func (d *DefinitionList) generatePackageDocs(name string) {
	options := packager.BuildOptions()
	options["generate_docs"] = true
	pkg := packager.NewPackage(packager.DefaultPackagePath, options)
	pkg.Load(name)

	for tindex, ttype := range pkg.Types {
		ttypeString := null.GetString(ttype.Name)

		for _, fun := range pkg.Functions {
			stub := FuncStub(pkg.Package, fun)

			if tindex == int(null.GetInt32(fun.ScopeTypeId)) && d.Definitions[ttypeString][stub] == nil {

				function := &FunctionDefinition{
					Name:        null.GetString(fun.Name),
					ParentScope: ttypeString,
					ShortStub:   ShortFuncStub(pkg.Package, fun),
					PackageName: name,
				}
				function.setID()
				description := null.GetString(fun.Description)

				if len(description) > 0 {
					lines := make([]string, 0)

					// Trim the description. Haml doesn't like extra new lines
					for _, line := range strings.Split(description, "\n") {
						if len(strings.TrimLeft(line, " \r\n")) > 0 {
							lines = append(lines, line)
						}
					}

					//function.Description = description

					// Hacky ... I need a way to specify the indent level to play nice w haml:
					function.Description = strings.Join(lines, "\n        ")
				}

				// Description / Examples will come when we can look at comment nodes

				function.Stub = stub
				segments := strings.Split(function.Stub, ")")

				function.CallPattern = segments[0] + ")"

				function.ReturnType = fun.ReturnTypeString(pkg.Package)
				function.YieldType = fun.OpensTypeString(pkg.Package)

				//println("Getting body for function: " + stub + " from package : " + name)
				ancestralScope, ancestralStub := d.findAncestralFunction(pkg.Package, fun)

				if ancestralScope != nil {
					//println("Found ancestral function in scope:" + *ancestralScope)
					ancestralFunction := d.Definitions[*ancestralScope][*ancestralStub]

					delete(d.Definitions[*ancestralScope], *ancestralStub) // Delete it

					//println("Loading body from package:" + ancestralFunction.PackageName)
					function.Body = getBody(ancestralFunction.PackageName, fun)
				} else {
					function.Body = getBody(name, fun)
				}

				// Hacky ... I need a way to specify the indent level for the body text to play nice w haml:
				function.Body = strings.Join(strings.Split(function.Body, "\n"), "\n            ")

				if d.Definitions[ttypeString] == nil {
					d.Definitions[ttypeString] = make(map[string]*FunctionDefinition)
				}
				d.Definitions[ttypeString][stub] = function
			}
		}
	}

	return
}
Beispiel #14
0
func resolveDefinition(pkg *tp.Package, fun *tp.Function, path string) {
	linkingContext := linker.NewLinkingContext(pkg)

	//	pkg.Log.Infof("\t -- Resolving --\n")
	//	pkg.Log.Infof("\t\t -- function: %v\n", fun)

	// Re-uses linker's logic to resolve function definitions
	if null.GetBool(fun.BuiltIn) == false {
		typeName := null.GetString(fun.ScopeType)

		// DON'T DO THE FOLLOWING HERE -- NEED TO RESOLVE INHERITANCE FIRST
		// // Make sure we're not replacing an existing function bacause it's (currently) a security risk
		// typeID := fun.GetScopeTypeId()
		// siblingFuncs := linkingContext.FunctionsIn(typeID)
		// // println("CHECKING FOR FRATRICIDE IN", typeName)
		// _, present := siblingFuncs[fun.Stub(pkg)]
		// if present {
		// 	msg := fmt.Sprintf("Redefining an existing function is not permitted: %s", fun.Stub(pkg))
		// 	panic(msg)
		// }
		// // for name, sib := range siblingFuncs {
		// // 	println("\t", name, sib)
		// // }
		// /////////////////////////////////////////////////////////////////////////////

		if len(typeName) != 0 {
			// When I pass in functions from the inheritance resolver, they're typeId is already set
			fun.ScopeTypeId = pkg.GetProtoTypeId(fun.ScopeType)
			fun.ScopeType = nil
		}

		localScope := make(linker.LocalDef, len(fun.Args))

		//		fun.ReturnTypeId = pkg.GetProtoTypeId(fun.ReturnType)
		for _, arg := range fun.Args {
			argTypeName := arg.TypeString
			var argTypeId int

			if argTypeName != nil {
				// Similar deal. Input functions from inheritance resolution already have ids set

				arg.TypeId = pkg.GetProtoTypeId(arg.TypeString)
				//println("Processing %", null.GetString(arg.Name))
				argTypeId = pkg.GetTypeId(null.GetString(arg.TypeString))
				arg.TypeString = nil
			} else {
				argTypeId = int(null.GetInt32(arg.TypeId))
			}

			localScope[null.GetString(arg.Name)] = argTypeId
		}

		//pkg.Log.Infof("Some insitruction: %v, %s", fun.Instruction, null.GetString(fun.Name) )
		scopeTypeId := int(null.GetInt32(fun.ScopeTypeId))
		//pkg.Log.Infof("\t\t -- opening scope type : %v\n", scopeTypeId)
		returnType := linkingContext.ProcessInstructionWithLocalScope(fun.Instruction, scopeTypeId, localScope, *fun.Name, path, false)

		if linkingContext.HasErrors() {
			message := ""
			for _, msg := range linkingContext.Errors {
				message = message + "\n" + msg
			}
			panic(message)
		}

		fun.ReturnTypeId = proto.Int32(int32(returnType))
		if fun.Instruction != nil {
			fun.Instruction.IterateAll(func(ins *tp.Instruction) {
				if *ins.Type == constants.Instruction_FUNCTION_CALL {
					if null.GetString(ins.Value) == "yield" {
						fun.OpensTypeId = ins.YieldTypeId
					}
				}
			})
		}

	}
	//pkg.Log.Infof("\t\t -- done --\n")
}
Beispiel #15
0
func (pkg *Package) resolveFunctionDescendants(fun *tp.Function) {

	// Check if this function contains any types that have descendants
	// name := fun.Stub(pkg.Package)
	// pkg.Log.Infof("Checking for inheritance on function: %v", name)

	newFun := &tp.Function{}
	inherit := false

	// Iterate over ScopeType, Arg types, return Type, opens Type

	// ScopeType

	thisTypeId := null.GetInt32(fun.ScopeTypeId)
	newType := pkg.Package.FindDescendantType(thisTypeId)

	if newType != -1 {
		if !inherit {
			// pkg.Log.Infof("\t -- ScopeType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name))
			newFun = fun.Clone().(*tp.Function)
			// pkg.Log.Infof("\t -- New fun: %v", newFun)
			inherit = true
		}
		// pkg.Log.Infof("\t -- Resetting scopeId")
		newFun.ScopeTypeId = proto.Int32(int32(newType))
	}

	// ReturnType

	thisTypeId = null.GetInt32(fun.ReturnTypeId)
	newType = pkg.Package.FindDescendantType(thisTypeId)

	if newType != -1 {
		if !inherit {
			// pkg.Log.Infof("\t -- ReturnType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name))
			newFun = fun.Clone().(*tp.Function)
			// pkg.Log.Infof("\t -- New fun: %v", newFun)
			inherit = true
		}
		// pkg.Log.Infof("\t -- Resetting returnId")
		newFun.ReturnTypeId = proto.Int32(int32(newType))
	}

	// OpensType

	thisTypeId = null.GetInt32(fun.OpensTypeId)
	newType = pkg.Package.FindDescendantType(thisTypeId)

	if newType != -1 {

		if !inherit {
			// pkg.Log.Infof("\t -- OpensType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name))
			newFun = fun.Clone().(*tp.Function)
			// pkg.Log.Infof("\t -- New fun: %v", newFun)
			inherit = true
		}
		// pkg.Log.Infof("\t -- Resetting openTypeId")
		newFun.OpensTypeId = proto.Int32(int32(newType))
	}

	// Arguments

	for index, arg := range fun.Args {
		thisTypeId = null.GetInt32(arg.TypeId)
		newType = pkg.Package.FindDescendantType(thisTypeId)

		if newType != -1 {

			if !inherit {
				// pkg.Log.Infof("\t -- ArgType : Found ancestral type. Cloning function %v\n", null.GetString(fun.Name))
				newFun = fun.Clone().(*tp.Function)
				// pkg.Log.Infof("\t -- New fun: %v", newFun)
				inherit = true
			}
			// pkg.Log.Infof("\t -- Resetting argument")
			newFun.Args[index].TypeId = proto.Int32(int32(newType))
		}

	}

	// pkg.Log.Infof("\t -- Old function: %v\n\t -- New function: %v\n", fun, newFun)

	if inherit {
		resolveDefinition(pkg.Package, newFun, "")
		pkg.Package.Functions = append(pkg.Package.Functions, newFun)
		// println("replicated", pkg.Package.GetTypeName(newFun.GetScopeTypeId()), newFun.Stub(pkg.Package))
	}

}
Beispiel #16
0
func (r *CheckResult) AddXpathWarning(obj *tp.ScriptObject, ins *tp.Instruction, message string) {
	warning := NewWarning(WARNING_XPATH, null.GetString(obj.Name), int(null.GetInt32(ins.LineNumber)), message)
	print("F")
	r.Warnings = append(r.Warnings, warning)
}
Beispiel #17
0
func (fun *Function) OpensTypeString(pkg2 protoface.Package) string {
	pkg := pkg2.(*Package)
	return pkg.GetTypeName(null.GetInt32(fun.OpensTypeId))
}