#!/usr/bin/env nomsu -V4.8.8.6
#
    This file contains basic error reporting code

use "core/metaprogramming.nom"

compile [barf] to (Lua "error(nil, 0);")
compile [barf %msg] to (Lua "error(\(%msg as lua expr), 0);")
compile [compile error at %source %msg] to (..)
    Lua "nomsu:compile_error(\(%source as lua expr), \(%msg as lua expr))"

compile [assume %condition] to:
    lua> "\
        ..local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition))"
    return (..)
        Lua "\
            ..if not \(%condition as lua expr) then
                error(\(quote "\%assumption"), 0)
            end"

compile [assume %a == %b] to:
    lua> "\
        ..local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\(\(%a == %b))))"
    define mangler
    return (..)
        Lua "\
            ..do
                local \(mangle "a"), \(mangle "b") = \(%a as lua expr), \(%b as lua expr)
                if \(mangle "a") ~= \(mangle "b") then
                    error(\(quote "\%assumption").."\\n"..tostring(\(mangle "a")).." != "..tostring(\(..)
                mangle "b"
            ..), 0)
                end
            end"

compile [assume %condition or barf %message] to (..)
    Lua "\
        ..if not \(%condition as lua expr) then
            error(\(%message as lua expr), 0)
        end"

test:
    try (barf) and if it succeeds: barf "try failed."
    %worked = (no)
    try (barf) and if it barfs: %worked = (yes)
    assume %worked or barf "try/catch failed"
    %x = 1
    try:
        %x = 2
        do (barf) then always: %x = 3
    ..and if it barfs: do nothing
    
    assume (%x == 3) or barf "do/then always failed"

# Try/except
compile [..]
    try %action and if it succeeds %success or if it barfs %msg %fallback
    try %action and if it barfs %msg %fallback or if it succeeds %success
..to (..)
    Lua "\
        ..do
            local fell_through = false
            local err, erred = nil, false
            local ok, ret = xpcall(function()
                \(%action as lua statements)
                fell_through = true
            end, function(\(%msg as lua expr))
                local ok, ret = pcall(function()
                    \(%fallback as lua statements)
                end)
                if not ok then err, erred = ret, true end
            end)
            if ok then
                \(%success as lua statements)
                if not fell_through then
                    return ret
                end
            elseif erred then
                error(err, 0)
            end
        end"

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

parse [..]
    try %action and if it succeeds %success or if it barfs %fallback
    try %action and if it barfs %fallback or if it succeeds %success
..as (try %action and if it succeeds %success or if it barfs (=lua "") %fallback)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

parse [try %action] as (..)
    try %action and if it succeeds (do nothing) or if it barfs (do nothing)

parse [try %action and if it barfs %fallback] as (..)
    try %action and if it succeeds (do nothing) or if it barfs %fallback

parse [try %action and if it barfs %msg %fallback] as (..)
    try %action and if it succeeds (do nothing) or if it barfs %msg %fallback

parse [try %action and if it succeeds %success] as (..)
    try %action and if it succeeds %success or if it barfs (do nothing)