Unisay / purescript-lua

Purescript compiler back-end for Lua
GNU General Public License v3.0
55 stars 2 forks source link

Linker error: Error parsing foreign file #16

Closed tomshackell closed 6 months ago

tomshackell commented 6 months ago

Hi,

I've been having a play with purescript lua, I tried to create a simple 'Hello World' example.

src/Main.purs:

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)

main :: Effect Unit
main = do
  log "Hello World!"

packages.dhall:

let upstream = 
    https://github.com/Unisay/purescript-lua-package-sets/releases/download/psc-0.15.9-20230704/packages.dhall
        sha256:bca5a6cc5bd5c95040951d412f773ba56da3a381852d9ac1f1f333b2a93abb80
in upstream

spago.dhall:

{ name = "pslua-test"
, dependencies = [ "console", "effect", "prelude" ]
, packages = ./packages.dhall
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
, backend ="pslua --foreign-path . --ps-output output --lua-output-file dist/pslua-test.lua --entry Main.main"
}

It all compiles fine until it gets to linking:

Linker error:
Error parsing foreign file "C:\\Dev\\pslua-test\\.spago\\console\\v6.0.0\\src\\Effect\\Console.lua":
C:\Dev\pslua-test\.spago\console\v6.0.0\src\Effect\Console.lua:3:11:
  |
3 |     log = function(s) return function() print(s) end end,
  |           ^
unexpected 'f'
expecting '(' or white space

PS Lua: compiling ...
[error] Backend "pslua --foreign-path . --ps-output output --lua-output-file dist/pslua-test.lua --entry Main.main" exited with error:1

This is using pslua compiled from source (latest on github) on Windows platform.

~Looks like it's maybe trying to parse the lua as Javascript? Maybe a bug, or maybe I'm doing something wrong.~ Ah no I worked it out the problem is the code in Foreign.hs is expecting the values in ()s, so this is a problem with the Console library.

Unisay commented 6 months ago

Hi @tomshackell and thanks for reporting!

I did a partial rework in the way foreign imports are processed recently and didn't properly document the new syntax yet, sorry for your frustration.

The goal was (and still is) to enable more optimisations (elimination of unused foreign bindings, inlining). For this reason I couldn't treat foreign modules as large blobs of Lua anymore, but instead needed to make them more like a maps where keys are names and values are corresponding Lua expressions.

Unfortunately this required pslua to parse foreign Lua scripts. I didn't implement a full-fledged Lua parser but instead made something shallow, that is capable of parsing a top level only. For this I had to require Lua expression to be surrounded by braces. For example:

Before foreign modules were like this:

local foo = 42
return {
  moreFoo = foo + 1,
  lessFoo = foo - 1,
}

Now they need to be like this:

local foo = 42
return {
  moreFoo = (foo + 1),
  lessFoo = (foo - 1),
}

After introducing this change I changed libraries to the new syntax, but I might have missed some. In your case the error comes from the Effect\Console.lua which has been already migrated, so you can fix the error by updating to the newest packages set. Try this in your packages.dhall:

let upstream-ps =
      https://github.com/purescript/package-sets/releases/download/psc-0.15.15-20240320/packages.dhall
        sha256:ae8a25645e81ff979beb397a21e5d272fae7c9ebdb021a96b1b431388c8f3c34

let upstream-lua =
      https://github.com/Unisay/purescript-lua-package-sets/releases/download/psc-0.15.15-20240337/packages.dhall
        sha256:1bbe483b76cd20cdbb77eb202013f96047093281559b7a319cae443ae0eba453

in  upstream-ps // upstream-lua

making sure you're using Purescript 0.15.15.

If you're using nix then you can use this flake:

{
  description = "Purescript-Lua Flake";

  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    nixpkgs.url = "nixpkgs/nixos-unstable";
    easyps = {
      url = "github:justinwoo/easy-purescript-nix";
      flake = false;
    };
    pslua.url = "github:Unisay/purescript-lua";
  };

  outputs = { self, nixpkgs, flake-utils, easyps, pslua }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        p = nixpkgs.legacyPackages.${system};
        e = import easyps { pkgs = p; };
        l = p.lua51Packages;
      in {
        devShell = p.mkShell {
          buildInputs = [
              p.dhall
              l.lua
              l.luacheck
              p.luaformatter
              p.nixfmt-rfc-style
              pslua.packages.${system}.default
              e.purs-0_15_15
              e.purs-tidy
              e.spago
              p.treefmt
            ];
        };
      });
}

P.S. Thanks for trying this project, I'd like to support you in your experiments, so please don't give up if something doesn't work yet :)

tomshackell commented 6 months ago

Thanks, yes that's fixed it. I did have a go changing the package-set but I couldn't get it to work (I find spago a bit confusing TBPH). Maybe worth updating the dependencies in your example project as that's where I copied it from?

~I have another issue I'll raise separately as well :-)~ Ah no, worked it out: I needed Effect.Uncurried(EffectFn1, runEffectFn1) not Data.Functions.Uncurried(Fn1, runFn1).

Unisay commented 6 months ago

Maybe worth updating the dependencies in your example project as that's where I copied it from?

100%, doing it rn.