This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
LeDark Lua's profile picture

[Parse] How to make functions.

Started by LeDark Lua, 28 August 2015 - 10:14 AM
LeDark Lua #1
Posted 28 August 2015 - 12:14 PM
So I know how to capture a function with the parser but I dont know how to assign the function and then have like variables in () theese and such:

func helloWorld( $str="Hello world" )
   print $str
end

helloWorld()
--Output: Hello world

helloWorld "Hello, world!"
--Output: Hello, world!


Thanks in advance.

LeDark Lua
Edited on 28 August 2015 - 10:15 AM
Exerro #2
Posted 28 August 2015 - 12:28 PM
Sorry what? What exactly are you asking? Are you interpreting this and running in a VM or compiling to Lua? If running in a VM, how are you doing so?
LeDark Lua #3
Posted 28 August 2015 - 12:30 PM
Im running in VM here:

http://pastebin.com/3hs9yYq2

Example code in this VM:

http://pastebin.com/aiCQ586M
Edited on 28 August 2015 - 10:31 AM
Exerro #4
Posted 28 August 2015 - 01:56 PM
But what's the problem? You can parse a function, but you don't know how to call it, execute it, and handle its scope?
LeDark Lua #5
Posted 28 August 2015 - 02:44 PM
yes. your are right.
Exerro #6
Posted 28 August 2015 - 04:02 PM
Well I have no idea how your code works really, but if I'm halfway through writing my own language now anyway, so I'll tell you what I've done.

1) Lex it - turn the source into a list of tokens (you've done this, but a token to me is a table with type and value, i.e. number 5, word "hello", etc)
2) Parse it - go through the tokens, turning it into an AST, for example (word "x", symbol "=", number 5) could eval to a "set" statement.

After this, it will be down to the compiler to turn the AST into a set of linear instructions for the VM to execute. This is the best way to get a fast language I'd say, but you can just run the code straight from the AST if you really want to. I'll describe what goes on in the compiler, but you can follow a similar method to make it run straight away rather than turning it into a list of instructions.

Every 'block' has a scope. For example, in an if statement in Lua, any local you define isn't set globally, and once the if statement exits, the variable is no longer accessible. A function also has its own scope when you define it. If it has parameters, those parameters are localised in the new scope, meaning any reference to them are a reference to the parameters, not an upvalue. For example, take this code example.

local y = 1
local function a( x ) --> x is local to this function
    print( x ) --> looks for 'x' in top scope (function scope), finds it, so x is refering to 'x' of the function scope
    print( y ) --> looks for 'y' in the top scope (function scope), doesn't find it, so looks for it as an upvalue (and finds it)
end

I translate the variables into numbers. Here, y would be 0, a would be 1, and x would be 2, because that is the order in which they were defined. When you called a, it would set index 2 to whatever you called it with, then when the function tried to access 'x', it would look in index 2.
LeDark Lua #7
Posted 28 August 2015 - 04:13 PM
The problem is I dont know how to make this kind of code. I think of this:

I have a table which stores the functions. When the function is called I make the passing variable like so:

func a( $x="test" )
   print( x )
end

a "Hi"

--[[VM does this:
   x = "a:var x= string hi"
--]]


Really I dont know how to make functions even if you explained how.
So right now I like the SimpleLex system because im new to Lua "Few ( up to: 2 - 5 ) months"
And parser is Simple too.

Well ill try but ill fail.
Exerro #8
Posted 28 August 2015 - 04:53 PM
Can you explain how functions are stored a bit better please?
LeDark Lua #9
Posted 28 August 2015 - 06:07 PM
So ok I will store the functions name in the table:

functions={}
Then when I assign it:

function addFunc(funcName, code)
   functions[funcName]=code
end
If I want to run it:

function runFunc(funcName)
   parse(functions[funcName])
end

So now how to pass the input?
Edited on 28 August 2015 - 04:09 PM
Exerro #10
Posted 28 August 2015 - 06:21 PM
Maybe parse( tokens, scope )?
LeDark Lua #11
Posted 28 August 2015 - 06:40 PM
No. I was trying to do the code. I almost got it doing in this forums. But I failed because I realized that when calling I dont pass the variable contents.


func do($test="default")
   print $test
end

--This would print the "default" only because I dont know how to pass that "weird stuff." string.
do "weird stuff."
Edited on 28 August 2015 - 04:42 PM
Exerro #12
Posted 28 August 2015 - 06:43 PM
When you call a function, it currently calls `parse( functionCodeTokenList )`, what I'm saying is that you should create a scope, probably just a table with __index pointing to _G or something, then add the function parameters to that and call `parse( functionCodeTokenList, functionScope )`.
LeDark Lua #13
Posted 28 August 2015 - 06:44 PM
yeah I know, but how to return values from defined variables for that specific function.
LeDark Lua #14
Posted 28 August 2015 - 07:35 PM
Oh ok I got it. Well I have the idea in my head but I will make that idea come true tomorow.
LeDark Lua #15
Posted 29 August 2015 - 11:07 AM
So ok, I made a function system. You cant define but you can run it. And you can run Lua code. But you need to add the function like so:

addFunc("HelloWorld", function()
   print("Hello, world!")
end)

Problem is with scopes. I can capture them but there are some problems.
If I will have a bug that I dont know how to fix I will paste it here.

Here is the code of the addFunc and runFunc but these aren't finished:

function addFunc(funcName, tokens, scope)
   functions[funcName]=tokens
   if scope then
	  local i=1
	  while i<=#scope do
		 local sc=scope[i+2]
		 if sc:sub(1, 3)=="NUM" then
			doASSIGN(scope[i], sc:sub(5))
			i=i+3
		 elseif sc:sub(1, 6)=="STRING" then
			doASSIGN(scope[i], sc:sub(9))
			i=i+3
		 elseif sc:sub(1, 4)=="EXPR" then
			doASSIGN(scope[i], sc:sub(6))
			i=i+3
		 elseif sc:sub(1, 3)=="VAR" then
			doASSIGN(scope[i], getVARIABLE(sc))
			i=i+3
		 end
	  end
	  functionScopes[funcName]=scope
   else
	  functionScopes[funcName]={}
   end
end

local function runFunc(funcName)
   if functions[funcName] then
	  if type(functions[funcName])=="table" then
		 parseFunc(functions[funcName], functionScopes[funcName])
	  elseif type(functions[funcName])=="function" then
		 if #functionScopes[funcName]<1 then
			functions[funcName]()
		 end
	  end
	  if functionScopes[funcName] then
		 for k, _ in pairs(functionScopes[funcName]) do
			symbols[k]=nil
		 end
	  end
   else
	  printError("Can't run a non existant function.")
   end
end
Edited on 29 August 2015 - 09:09 AM
LeDark Lua #16
Posted 29 August 2015 - 02:48 PM
Ok running functions inside the VM works. This is how it works.
VM Code. :
print arg1 arg2 … : is a function.

$number = 15
$helloWorld = "Hello, world!"

if $number == 15 then
   :print $helloWorld "Works!" :
endif

:print "No commas ',' WOOHOO!" :
Output:
Print function:

addFunc("print", function(input)
   local __str = ""
   for i=1, #input do
	  __str = __str..input[i].." "
   end
   print(__str)
end)
Edited on 29 August 2015 - 12:55 PM
Exerro #17
Posted 29 August 2015 - 05:24 PM
Nice, glad it works now :)/>