feat: better structured internal
This commit is contained in:
@@ -7,35 +7,37 @@ import (
|
||||
"time"
|
||||
|
||||
"git.maximhutz.com/max/lambda/internal/cli"
|
||||
"git.maximhutz.com/max/lambda/internal/config"
|
||||
"git.maximhutz.com/max/lambda/pkg/lambda"
|
||||
"git.maximhutz.com/max/lambda/pkg/parser"
|
||||
"git.maximhutz.com/max/lambda/pkg/tokenizer"
|
||||
)
|
||||
|
||||
// Run main application.
|
||||
func main() {
|
||||
|
||||
options, err := cli.ParseOptions(os.Args[1:])
|
||||
options, err := config.FromArgs()
|
||||
cli.HandleError(err)
|
||||
|
||||
logger := cli.GetLogger(*options)
|
||||
logger := options.GetLogger()
|
||||
logger.Info("Using program arguments.", "args", os.Args)
|
||||
logger.Info("Parsed CLI options.", "options", options)
|
||||
|
||||
if options.Input == "-" {
|
||||
options.Input, err = cli.ReadInput()
|
||||
cli.HandleError(err)
|
||||
}
|
||||
input, err := options.Source.Pull()
|
||||
cli.HandleError(err)
|
||||
|
||||
tokens, fails := tokenizer.GetTokens([]rune(options.Input))
|
||||
// Parse tokens.
|
||||
tokens, fails := tokenizer.GetTokens([]rune(input))
|
||||
if len(fails) > 0 {
|
||||
cli.HandleError(errors.Join(fails...))
|
||||
}
|
||||
logger.Info("Parsed tokens.", "tokens", tokens)
|
||||
|
||||
// Turn tokens into syntax tree.
|
||||
expression, err := parser.GetTree(tokens)
|
||||
cli.HandleError(err)
|
||||
logger.Info("Parsed syntax tree.", "tree", lambda.Stringify(expression))
|
||||
|
||||
// Reduce expression.
|
||||
start := time.Now()
|
||||
|
||||
if options.Explanation {
|
||||
|
||||
@@ -5,18 +5,24 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Arguments given to program.
|
||||
type CLIOptions struct {
|
||||
Input string
|
||||
Verbose bool
|
||||
// The source code given to the program.
|
||||
Input string
|
||||
// Whether or not to print debug logs.
|
||||
Verbose bool
|
||||
// Whether or not to print an explanation of the reduction.
|
||||
Explanation bool
|
||||
}
|
||||
|
||||
func ParseOptions(args []string) (*CLIOptions, error) {
|
||||
// Parse flags and arguments.
|
||||
// Extract the program configuration from the command-line arguments.
|
||||
func ParseOptions() (*CLIOptions, error) {
|
||||
// Parse flags.
|
||||
verbose := flag.Bool("v", false, "Verbosity. If set, the program will print logs.")
|
||||
explanation := flag.Bool("x", false, "Explanation. Whether or not to show all reduction steps.")
|
||||
flag.Parse()
|
||||
|
||||
// Parse non-flag arguments.
|
||||
if flag.NArg() == 0 {
|
||||
return nil, fmt.Errorf("No input given.")
|
||||
} else if flag.NArg() > 1 {
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// A helper function to handle errors in the program. If it is given an error,
|
||||
// the program will exist, and print the error.
|
||||
func HandleError(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ReadInput() (string, error) {
|
||||
data, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
11
internal/config/config.go
Normal file
11
internal/config/config.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package config
|
||||
|
||||
// Arguments given to program.
|
||||
type Config struct {
|
||||
// The source code given to the program.
|
||||
Source Source
|
||||
// Whether or not to print debug logs.
|
||||
Verbose bool
|
||||
// Whether or not to print an explanation of the reduction.
|
||||
Explanation bool
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
package cli
|
||||
package config
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
func GetLogger(o CLIOptions) *slog.Logger {
|
||||
// Define the correct logger for the program to use.
|
||||
func (this Config) GetLogger() *slog.Logger {
|
||||
var level slog.Level
|
||||
if o.Verbose {
|
||||
if this.Verbose {
|
||||
level = slog.LevelInfo
|
||||
} else {
|
||||
level = slog.LevelError
|
||||
35
internal/config/parse_from_args.go
Normal file
35
internal/config/parse_from_args.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Extract the program configuration from the command-line arguments.
|
||||
func FromArgs() (*Config, error) {
|
||||
// Parse flags.
|
||||
verbose := flag.Bool("v", false, "Verbosity. If set, the program will print logs.")
|
||||
explanation := flag.Bool("x", false, "Explanation. Whether or not to show all reduction steps.")
|
||||
flag.Parse()
|
||||
|
||||
// Parse non-flag arguments.
|
||||
if flag.NArg() == 0 {
|
||||
return nil, fmt.Errorf("No input given.")
|
||||
} else if flag.NArg() > 1 {
|
||||
return nil, fmt.Errorf("More than 1 command-line argument.")
|
||||
}
|
||||
|
||||
// Parse source type.
|
||||
var source Source
|
||||
if flag.Arg(0) == "-" {
|
||||
source = StdinSource{}
|
||||
} else {
|
||||
source = StringSource{data: flag.Arg(0)}
|
||||
}
|
||||
|
||||
return &Config{
|
||||
Source: source,
|
||||
Verbose: *verbose,
|
||||
Explanation: *explanation,
|
||||
}, nil
|
||||
}
|
||||
29
internal/config/source.go
Normal file
29
internal/config/source.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Defines the consumption of different types of input sources.
|
||||
type Source interface {
|
||||
// Get the data.
|
||||
Pull() (string, error)
|
||||
}
|
||||
|
||||
// A source coming from a string.
|
||||
type StringSource struct{ data string }
|
||||
|
||||
func (this StringSource) Pull() (string, error) { return this.data, nil }
|
||||
|
||||
// A source coming from standard input.
|
||||
type StdinSource struct{}
|
||||
|
||||
func (this StdinSource) Pull() (string, error) {
|
||||
data, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
Reference in New Issue
Block a user