Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tmu-hci committed Jul 14, 2024
0 parents commit 0cb711e
Show file tree
Hide file tree
Showing 77 changed files with 2,892 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.vscode
Binary file added NutMeg.jar
Binary file not shown.
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[kimura](https://script.meg.tokyo/)
58 changes: 58 additions & 0 deletions src/main/scala/tokyo/meg/script/NutMeg.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package tokyo.meg.script

import java.io.IOException

import scala.util._
import scala.util.chaining._

import tokyo.meg.script.io._
import tokyo.meg.script.util._
import tokyo.meg.script.lexer._
import tokyo.meg.script.parser._
import tokyo.meg.script.treewalker._
import tokyo.meg.script.treewalker.values._

@main def main(args: String*): Unit =
val path = if (args.length == 0) None else Some(args(0))

val reader = path match
case Some(path) => FileReader.open[Value](path)
case None => Reader.open[Value](System.in)

reader: reader =>
val cursor = Cursor(reader)
val lexer = Lexer(cursor)
val parser = Parser(lexer)
val ast = parser.parse()
val treeWalker = TreeWalker((ast, "."))

treeWalker.eval()
match {
case Failure(exception: IOException) =>
System.err.println(
path match
case Some(path) =>
s"An error occurred while processing the file \"$path\": ${exception.getMessage()}"

case _ =>
s"An error occurred while processing the input: ${exception.getMessage()}"
)

1

case Failure(exception: Throwable) =>
System.err.println(exception)
System.err.println(
s"An unexpected error occurred: ${exception.getMessage()}"
)
exception.printStackTrace()

1

case Success(value) =>
value match
case IntValue(value) => value.toInt
case RealValue(value) => value.toInt
case _ => 0

} pipe System.exit
26 changes: 26 additions & 0 deletions src/main/scala/tokyo/meg/script/io/FileReader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tokyo.meg.script.io

import java.io.{
BufferedReader,
File,
FileReader => JavaFileReader,
InputStreamReader,
FileInputStream
}
import java.nio.file.Paths

import scala.util._
import scala.util.chaining._

object FileReader:
def open[T](path: String): (FileReader => T) => Try[T] =
Reader.open(() => FileReader(path))

final class FileReader(val path: String) extends Reader(FileInputStream(path)):
val file = File(path)
val parentPath = Paths
.get(file.getAbsolutePath())
.normalize()
.getParent()
.toString()
.replaceAll("\\\\", "/")
47 changes: 47 additions & 0 deletions src/main/scala/tokyo/meg/script/io/Reader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tokyo.meg.script.io

import java.io.{BufferedReader, InputStream, InputStreamReader}
import java.nio.file.Paths

import scala.collection.mutable._
import scala.util._
import scala.util.chaining._

object Reader:
def open[T](stream: InputStream): (Reader => T) => Try[T] =
open(() => Reader(stream))

def open[T, U <: Reader](readerGenerator: () => U)(f: U => T): Try[T] =
var reader: Option[U] = None

Try:
reader = Some(readerGenerator())
f(reader.get)
.tap: _ =>
reader match
case Some(reader) => reader.close()
case None => ()

class Reader(val stream: InputStream):
private val reader = BufferedReader(InputStreamReader(stream, "UTF-8"))
private val joined = Stack[Reader]()

def readLine(): Option[String] =
if joined.length == 0 then
reader.readLine() match
case null => None
case line => Some(line)
else
joined.top.readLine() match
case None =>
joined.pop()
readLine()

case Some(line) => Some(line)

def join: Reader => Reader =
joined.push(_).pipe(_ => this)

def close(): Unit =
reader.close()
joined.foreach(_.close())
13 changes: 13 additions & 0 deletions src/main/scala/tokyo/meg/script/io/StringReader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package tokyo.meg.script.io

import java.io.ByteArrayInputStream

import scala.util._
import scala.util.chaining._

object StringReader:
def open[T](string: String): (StringReader => T) => Try[T] =
Reader.open(() => StringReader(string))

final class StringReader(val string: String)
extends Reader(ByteArrayInputStream(string.getBytes("UTF-8")))
94 changes: 94 additions & 0 deletions src/main/scala/tokyo/meg/script/lexer/Cursor.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package tokyo.meg.script.lexer

import scala.util.chaining._

import tokyo.meg.script.io._

final class Cursor(private val reader: Reader) extends Iterator[Char]:
val parentPath = reader match
case reader: FileReader => reader.parentPath
case _ => "."

private var _currentLine: Option[String] = Some("")
private var _atEof = false
private var (_line, _column) = (0, 1)
private var (_currentChar, _nextChar) = ('\n', '\n')

advance()

override inline def hasNext: Boolean =
!atEof

override inline def next(): Char =
currentChar tap advance

inline def currentLine: Option[String] =
_currentLine

inline def atEof: Boolean =
_atEof

inline def line: Int =
_line

inline def column: Int =
_column

inline def currentChar: Char =
_currentChar

inline def nextChar: Char =
_nextChar

def join: Reader => Cursor =
reader.join(_).pipe(_ => this)

@annotation.tailrec
def advance[T](value: T = this): T =
_currentChar = _nextChar

currentLine match
case None =>
_nextChar = '\u0000'
_atEof = 0 < column
_column += 1

value

case Some(string) =>
if string.length == column - 1
then fetchLine().advance(value)
else
_nextChar = if (string.length == column) '\n' else string(column)
_column += 1

value

def insert(deleteCount: Int, string: String): Unit =
currentLine match
case Some(currentLine) =>
_currentLine = Some(
currentLine.slice(0, column - deleteCount - 1)
+ string
+ currentLine.slice(column - 1, currentLine.length)
)

_column -= deleteCount - 1
_currentChar = _currentLine.get(column - 2)
_nextChar = try _currentLine.get(column - 1) catch _ => '\n'

case _ => ()

private def fetchLine[T](value: T = this): T =
_currentLine = reader.readLine()
_column = 0

currentLine match
case Some(nextLine) =>
_line += 1

if nextLine.filter(_.isWhitespace) == nextLine
then fetchLine(value)
else value

case _ => value
Loading

0 comments on commit 0cb711e

Please sign in to comment.