Skip to content

Commit

Permalink
Plumb errors and stuff through for multi-file programs
Browse files Browse the repository at this point in the history
  • Loading branch information
dusty-phillips committed Aug 25, 2024
1 parent f6d6bab commit 38a9a4e
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 53 deletions.
17 changes: 17 additions & 0 deletions src/compiler.gleam
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import compiler/generator
import compiler/program
import compiler/transformer
import glance
import gleam/dict
import gleam/result

// called only by unit tests
// todo: remove
pub fn compile(module_contents: String) -> Result(String, glance.Error) {
module_contents
|> glance.module
|> result.map(transformer.transform)
|> result.map(generator.generate)
}

pub fn compile_module(glance_module: glance.Module) -> String {
glance_module
|> transformer.transform
|> generator.generate
}

pub fn compile_program(program: program.GleamProgram) -> program.CompiledProgram {
program.CompiledProgram(
modules: program.modules
|> dict.map_values(fn(_key, value) { compile_module(value) }),
)
}
31 changes: 18 additions & 13 deletions src/program_parser.gleam → src/compiler/program.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@
//// filesystem.
//// It does not write to the filesystem.

import compiler/python
import errors
import glance
import gleam/dict
import gleam/list
import gleam/result
import pprint
import simplifile

pub type ParseError {
FileReadError(module: String, error: simplifile.FileError)
GlanceParseError(glance.Error)
}

pub type GleamProgram {
GleamProgram(modules: dict.Dict(String, glance.Module))
}

pub type CompiledProgram {
CompiledProgram(modules: dict.Dict(String, String))
}

/// Load the entry_point file and recursively load and parse any modules it
///returns.
pub fn load_program(entry_point: String) -> Result(GleamProgram, ParseError) {
pub fn load_program(entry_point: String) -> Result(GleamProgram, errors.Error) {
GleamProgram(modules: dict.new())
|> load_module(entry_point)
}
Expand All @@ -33,16 +34,16 @@ pub fn load_program(entry_point: String) -> Result(GleamProgram, ParseError) {
fn load_module(
program: GleamProgram,
module_path: String,
) -> Result(GleamProgram, ParseError) {
) -> Result(GleamProgram, errors.Error) {
pprint.debug(module_path)
case dict.get(program.modules, module_path) {
Ok(_) -> Ok(program)
Error(_) -> {
let module_result =
module_path
|> simplifile.read
|> result.map_error(FileReadError(module_path, _))
|> result.try(parse)
|> result.map_error(errors.FileReadError(module_path, _))
|> result.try(parse(_, module_path))

case module_result {
Error(err) -> Error(err)
Expand All @@ -57,18 +58,22 @@ fn load_module(
}

fn fold_load_module(
program_result: Result(GleamProgram, ParseError),
program_result: Result(GleamProgram, errors.Error),
import_def: glance.Definition(glance.Import),
) -> Result(GleamProgram, ParseError) {
) -> Result(GleamProgram, errors.Error) {
case program_result {
Error(error) -> Error(error)
Ok(program) ->
load_module(program, import_def.definition.module <> ".gleam")
}
}

fn parse(contents: String) -> Result(glance.Module, ParseError) {
glance.module(contents) |> result.map_error(GlanceParseError)
fn parse(
contents: String,
filename: String,
) -> Result(glance.Module, errors.Error) {
glance.module(contents)
|> result.map_error(errors.GlanceParseError(_, filename, contents))
}

fn add_module(
Expand Down
19 changes: 19 additions & 0 deletions src/errors.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import glance
import internal/errors as internal
import simplifile

pub type Error {
FileReadError(module: String, error: simplifile.FileError)
FileWriteError(module: String, error: simplifile.FileError)
GlanceParseError(error: glance.Error, module: String, contents: String)
}

pub fn format_error(error: Error) -> String {
case error {
FileReadError(filename, simplifile.Enoent) -> "File not found " <> filename
FileReadError(filename, _) -> "Unable to read " <> filename
FileWriteError(filename, _) -> "Unable to write " <> filename
GlanceParseError(error, filename, contents) ->
internal.format_glance_error(error, filename, contents)
}
}
49 changes: 20 additions & 29 deletions src/internal/errors.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import gleam/string
import glexer
import glexer/token
import internal/bytes
import pprint

pub fn format_glance_error(
error: glance.Error,
filename: String,
contents: String,
) -> String {
pprint.debug(error)
let error_message = case error {
glance.UnexpectedEndOfInput -> "Unexpected EOF"
glance.UnexpectedToken(token, position) ->
Expand Down Expand Up @@ -61,29 +59,27 @@ pub fn format_unexpected_token(
<> format_token(token)
<> " at position "
<> int.to_string(position_state.target_position)
_ ->
{
let column =
position_state.target_position
- position_state.current_line_first_byte_position
"Unexpected Token "
<> format_token(token)
<> "\nAt line "
<> int.to_string(position_state.current_line_number)
<> " column "
<> int.to_string(column)
<> "\n\n"
<> {
position_state.current_line_bytes
|> bytes_builder.to_bit_array
|> bit_array.to_string
|> result.unwrap("Unexpected unicode")
}
<> "\n"
<> string.repeat(" ", column - 1)
<> "^\n"
_ -> {
let column =
position_state.target_position
- position_state.current_line_first_byte_position
"Unexpected Token "
<> format_token(token)
<> "\nAt line "
<> int.to_string(position_state.current_line_number)
<> " column "
<> int.to_string(column)
<> "\n\n"
<> {
position_state.current_line_bytes
|> bytes_builder.to_bit_array
|> bit_array.to_string
|> result.unwrap("Unexpected unicode")
}
|> pprint.debug
<> "\n"
<> string.repeat(" ", column - 1)
<> "^\n"
}
}
}

Expand All @@ -94,10 +90,6 @@ fn fold_position_to_lines(
state: PositionState,
byte: Int,
) -> list.ContinueOrStop(PositionState) {
pprint.debug(#(
PositionState(..state, current_line_bytes: bytes_builder.new()),
byte,
))
case byte, state.current_position, state.target_position {
10, curr, target if curr < target ->
list.Continue(
Expand Down Expand Up @@ -128,7 +120,6 @@ fn format_token(token: token.Token) -> String {
case token {
token.Int(num_str) -> num_str
_ -> {
pprint.debug(token)
"<TODO Unknown Token>"
}
}
Expand Down
21 changes: 14 additions & 7 deletions src/macabre.gleam
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import argv
import compiler
import gleam/dict
import compiler/program
import errors
import gleam/io
import gleam/result
import gleam/string
import internal/errors
import internal/errors as error_functions
import output
import pprint
import program_parser
import simplifile

pub fn usage(message: String) -> Nil {
Expand All @@ -20,7 +20,11 @@ fn compile_module(filename: String) -> Result(Nil, String) {
|> result.try(fn(content) {
content
|> compiler.compile
|> result.map_error(errors.format_glance_error(_, filename, content))
|> result.map_error(error_functions.format_glance_error(
_,
filename,
content,
))
})
|> result.try(output.write(_, output.replace_extension(filename)))
|> result.try(fn(_) {
Expand All @@ -40,9 +44,12 @@ pub fn main() {
False -> usage(input <> ":" <> " Not a gleam input file")
True -> {
input
|> program_parser.load_program()
|> pprint.debug
Nil
|> program.load_program
|> result.map(compiler.compile_program)
|> result.try(output.write_program(_, "build"))
|> result.map_error(output.write_error)
|> result.unwrap_both
// both nil
}
}
[_, _, ..] -> usage("Too many arguments")
Expand Down
21 changes: 18 additions & 3 deletions src/output.gleam
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import compiler/program
import errors
import filepath
import gleam/io
import gleam/result
import python_prelude
import simplifile

pub fn write(contents: String, filename: String) -> Result(Nil, String) {
pub fn write(contents: String, filename: String) -> Result(Nil, errors.Error) {
simplifile.write(filename, contents)
|> result.replace_error("Unable to write to '" <> filename <> "'")
|> result.map_error(errors.FileWriteError(filename, _))
}

pub fn replace_extension(filename: String) -> String {
fn replace_extension(filename: String) -> String {
filename |> filepath.strip_extension <> ".py"
}

Expand All @@ -36,3 +38,16 @@ pub fn write_prelude_file(filepath: String) -> Result(Nil, String) {
|> simplifile.write(python_prelude.gleam_builtins)
|> result.replace_error("Unable to write prelude")
}

pub fn write_program(
program: program.CompiledProgram,
directory: String,
) -> Result(Nil, errors.Error) {
todo
}

pub fn write_error(error: errors.Error) -> Nil {
error
|> errors.format_error
|> io.println
}
1 change: 0 additions & 1 deletion test/internal/errors_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ pub fn position_in_second_line_test() {
}

pub fn position_after_newline_test() {
pprint.debug("abc\n\nd5fg")
errors.format_unexpected_token(
token.Int("5"),
glexer.Position(6),
Expand Down

0 comments on commit 38a9a4e

Please sign in to comment.