Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

undefined variable should not be syntax error #1

Closed
johnd0e opened this issue Mar 12, 2023 · 9 comments
Closed

undefined variable should not be syntax error #1

johnd0e opened this issue Mar 12, 2023 · 9 comments

Comments

@johnd0e
Copy link

johnd0e commented Mar 12, 2023

assert(require"moocscript.core".loadstring("print(a)"))
[string "assert(require"moocscript.core".loadstring("p..."]:1: Error: undefined variable
File: _
Line: 1 (Pos: 6)
Source: print(a)
              ^

This is breaking change, as Lua's std loadstring is not so strict.
And this is in many cases just wrong, because it is just impossible to make such assumption not taking into account function's ENV.

@lalawue
Copy link
Owner

lalawue commented Mar 13, 2023

assert(require"moocscript.core".loadstring("print(a)"))
[string "assert(require"moocscript.core".loadstring("p..."]:1: Error: undefined variable
File: _
Line: 1 (Pos: 6)
Source: print(a)
              ^

This is breaking change, as Lua's std loadstring is not so strict. And this is in many cases just wrong, because it is just impossible to make such assumption not taking into account function's ENV.


you are right, mooncake was very strict about global variable usage, when using core library's loadstring to transpile moocscript to Lua.

I think this is an advantage of mooncake, there will be less global variable pollution when code base becoming larger.

there's two type of error in this code, I try to figure out what's happening:

assert(require"moocscript.core".loadstring("print(a)"))

  1. first is syntax error, function call's normal form in mooncake should enclosed by parenthesis, otherwise parser will raise an error:
➜  /tmp moocscript -v
moocscript v0.8.20221204, LuaJIT 2.1.0-beta3
➜  /tmp cat a.mooc
assert(require"moocscript.core".loadstring("print(a)"))
➜  /tmp moocscript a.mooc
Error: invalid token 'string', when expected ')'
File: a.mooc
Line: 1 (Pos: 14)
Source: assert(require"moocscript.core".loadstring("print(a)"))
                      ^

  1. the correct syntax of this code:
assert(require("moocscript.core").loadstring("print(a)"))

and mooncake can transpile it to Lua, this time only treat "print(a)" as a string.

➜  /tmp cat b.mooc
assert(require("moocscript.core").loadstring("print(a)"))
➜  /tmp moocscript -s b.mooc
assert(require("moocscript.core").loadstring("print(a)"))

3. when really running, core library's loadstring will raise an error for transpile "print(a)" to Lua, for variable `a` undefined in source string all level scopes.
➜  /tmp moocscript b.mooc
~/rocks/bin/luajit: [string "b.mooc"]:1: Error: undefined variable
File: _
Line: 1 (Pos: 6)
Source: print(a)
              ^
stack traceback:
	[C]: in function 'assert'
	[string "b.mooc"]:1: in function 'f'
	...uarocks/rocks-5.1/mooncake/0.8.20221204-2/bin/moocscript:119: in function 'main'
	...uarocks/rocks-5.1/mooncake/0.8.20221204-2/bin/moocscript:243: in main chunk
	[C]: at 0x0104b67a70

4. if you really know it will running well for bring pre-defined `a` from `setfenv` or `_ENV`, you can using `export` keyword like
assert(require("moocscript.core").loadstring("export a; print(a)"))

or you can using Lua's loadstring directly

assert(loadstring("print(a)"))

@lalawue lalawue closed this as completed Mar 13, 2023
@johnd0e
Copy link
Author

johnd0e commented Mar 13, 2023

4a. With print(a) it was only small example. In fact all the mooncake code meant to be run in custom feature-rich environment with dozens of predefined functions and variables. It is completely counterproductive to include "export" for all of them to each small piece of code.
Ya, nobody likes "global variable pollution", but we use special tools to prevent this (like glorious luacheck).

4b. Sure we use Lua's loadstring for Lua code. But the intent was to load mooncake code.

So I have no other idea how to deal with it, except asking you to add some option to skip 'undefined variable' checks.

@lalawue
Copy link
Owner

lalawue commented Mar 14, 2023

4a. With print(a) it was only small example. In fact all the mooncake code meant to be run in custom feature-rich environment with dozens of predefined functions and variables. It is completely counterproductive to include "export" for all of them to each small piece of code. Ya, nobody likes "global variable pollution", but we use special tools to prevent this (like glorious luacheck).

4b. Sure we use Luas loadstringfor Lua code. But the intent was to loadmooncake` code.

So I have no other idea how to deal with it, except asking you to add some option to skip 'undefined variable' checks.

  • the mooncake only transpile .mooc source to Lua and only make sure all global variable in .mooc are exported before using

  • for you don't need local variable before define and using it

  • if you like using global variable more than local, export * in the file begining is enough, the compiler will not check this any more, further more, if you need project scope global variable, read source and change it for yourself

  • mooncake only transpile .mooc and will not affect your .lua source, you can require .mooc from .luaor require .lua form .mooc

  • you can transpile all your .mooc to .lua before runing it, and then no one will stop you using special tools to lint Lua code, like glorious luacheck

  • you know something typescript, right?

  • I think you can put your eyes on other mooncake's features, for using global variable directly is quit easy to by pass by tanspiler if you really want to

@johnd0e
Copy link
Author

johnd0e commented Mar 15, 2023

Unfortunately export * is completely irrelevant to my task, because I still want all the definitions to be local by default.
What I exactly need is the possibility to write in mooc (for example) a = b and get it transpiled into Lua as local a = b without checking whether b was defined before.

I need it because the function meant to be executed in rich environment, with a lot of variables predefined.
Mooncake just does not know anything about that target environment, because it is not in the source.

I think you can put your eyes on other mooncake's features, for using global variable directly is quit easy to by pass by tanspiler if you really want to

Sorry, I have not got what you meant.
Sure I have looked through docs, but not found any solution.

@lalawue
Copy link
Owner

lalawue commented Mar 17, 2023

Sure I have looked through docs, but not found any solution.

Unfortunately I did not know why you want an undefined right-value, but mooncake is very strict to right-value to be defined first.

Sorry, may be I don't know what you want.

Sure I insist on you should read docs, including sources first for your task, which is completely irrelevant to me.

Whish the MIT lincesed sources will help you.

@johnd0e
Copy link
Author

johnd0e commented Mar 17, 2023

Unfortunately I did not know why you want an undefined right-value

Because it is actually defined, not in the source yourself, but in environment.
Consider such Lua example:

local ENV = {some_predefined_function=function (x)
 -- ...
end}

local mcore = require("mooncake.core")
local fn = assert(mcore.loadstring([[
  a = some_predefined_function(12345)
  -- ...
]]))
setfenv(fn, ENV)
f()

@lalawue lalawue reopened this Mar 18, 2023
@lalawue
Copy link
Owner

lalawue commented Mar 18, 2023

Unfortunately I did not know why you want an undefined right-value

Because it is actually defined, not in the source yourself, but in environment. Consider such Lua example:

local ENV = {some_predefined_function=function (x)
 -- ...
end}

local mcore = require("mooncake.core")
local fn = assert(mcore.loadstring([[
  a = some_predefined_function(12345)
  -- ...
]]))
setfenv(fn, ENV)
f()

you can export * in the very beginning of the loading string

local ENV = {some_predefined_function=function (x)
 -- ...
end}
setmetatable(ENV, { __index = _G })

local mcore = require("moocscript.core")
local fn = assert(mcore.loadstring('export *' .. [[
  a = some_predefined_function(12345)
]]))
setfenv(fn, ENV)
fn()

@lalawue lalawue closed this as completed Mar 18, 2023
@johnd0e
Copy link
Author

johnd0e commented Mar 18, 2023

you can export * in the very beginning of the loading string

The problem is that export * makes all variables global by default, which is far from my intentions.
I still want variables to be local by default, as advertised in docs: https://github.com/lalawue/mooncake#features
Consider this example:

  export *
  fn x() {
    a = 1
    return a
  }
  a = 2
  x()
  print(a) --expect 2 but get 1

And using global by default rule I get environment polluted with unneeded identifiers

@lalawue lalawue reopened this Mar 18, 2023
@lalawue
Copy link
Owner

lalawue commented Mar 18, 2023

you can export * in the very beginning of the loading string

The problem is that export * makes all variables global by default, which is far from my intentions. I still want variables to be local by default, as advertised in docs: https://github.com/lalawue/mooncake#features Consider this example:

  export *
  fn x() {
    a = 1
    return a
  }
  a = 2
  x()
  print(a) --expect 2 but get 1

And using global by default rule I get environment polluted with unneeded identifiers

  export *
  fn x() {
    local a = 1
    return a
  }
  local a = 2
  x()
  print(a) -- get 2

you can using like Lua this way, or using more strict the other way, anyway you have all the sources.

@lalawue lalawue closed this as completed Mar 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants