Skip to content

Commit

Permalink
LSP: Beginning a language server (#511)
Browse files Browse the repository at this point in the history
Right now all it does is listen to stdin, and write the messages it
receives to a log file. But, quite a few standard library functions
needed to be added to get to this point.
  • Loading branch information
kengorab authored Dec 10, 2024
1 parent 4e21e04 commit 59913dd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
2 changes: 2 additions & 0 deletions projects/lsp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
log.txt
18 changes: 18 additions & 0 deletions projects/lsp/src/main.abra
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import "process" as process
import "fs" as fs

val cwd = fs.getCurrentWorkingDirectory()
val logFilePath = "$cwd/log.txt"
val logFile = match fs.createFile(logFilePath, fs.AccessMode.WriteOnly) {
Ok(v) => v
Err(e) => {
println(e)
process.exit(1)
}
}

val stdin = process.stdin()

while stdin.readAsString() |str| {
logFile.writeln(str)
}
27 changes: 21 additions & 6 deletions projects/std/src/fs.abra
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export enum FileIOError {
}

export func readFile(path: String): Result<String, FileIOError> {
val fd = libc.open(path._buffer, libc.O_RDONLY)
val fd = libc.open(path._buffer, libc.O_RDONLY, 0)
if fd == -1 {
val errMsg = _strerror(libc.errno())
return Err(error: FileIOError.CouldNotOpen(message: errMsg))
Expand Down Expand Up @@ -42,6 +42,12 @@ export enum AccessMode {
ReadOnly
WriteOnly
ReadWrite

func _toUnderlying(self): Int = match self {
AccessMode.ReadOnly => libc.O_RDONLY
AccessMode.WriteOnly => libc.O_WRONLY
AccessMode.ReadWrite => libc.O_RDWR
}
}

export type File {
Expand Down Expand Up @@ -69,12 +75,21 @@ export type File {
}

export func openFile(path: String, accessMode: AccessMode): Result<File, FileIOError> {
val oflag = match accessMode {
AccessMode.ReadOnly => libc.O_RDONLY
AccessMode.WriteOnly => libc.O_WRONLY
AccessMode.ReadWrite => libc.O_RDWR
val oflag = accessMode._toUnderlying()
val fd = libc.open(path._buffer, oflag, 0)
if fd == -1 {
val errMsg = _strerror(libc.errno())
return Err(error: FileIOError.CouldNotOpen(message: errMsg))
}
val fd = libc.open(path._buffer, oflag)

Ok(File(_fd: fd, accessMode: accessMode))
}

export func createFile(path: String, accessMode: AccessMode): Result<File, FileIOError> {
var oflag = accessMode._toUnderlying() || libc.O_CREAT

val mode = 420 // 420 is 0644, but octal numbers aren't supported yet...
val fd = libc.open(path._buffer, oflag, mode)
if fd == -1 {
val errMsg = _strerror(libc.errno())
return Err(error: FileIOError.CouldNotOpen(message: errMsg))
Expand Down
6 changes: 5 additions & 1 deletion projects/std/src/libc.abra
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ export func strerror(errno: Int): Pointer<Byte>
export val O_RDONLY = 0
export val O_WRONLY = 1
export val O_RDWR = 2
export val O_CREAT = 512

@CBinding("open")
export func open(pathname: Pointer<Byte>, flags: Int): Int
export func open(pathname: Pointer<Byte>, flags: Int, mode: Int): Int

@CBinding("close")
export func close(fd: Int): Int
Expand All @@ -29,6 +30,9 @@ export func lseek(fd: Int, offset: Int, whence: Int): Int
@CBinding("read")
export func read(fd: Int, buf: Pointer<Byte>, count: Int): Int

@CBinding("stat")
export func stat(pathname: Pointer<Byte>, statbuf: Pointer<Byte>): Int

export val STDIN_FILENO = 0
export val STDOUT_FILENO = 1
export val STDERR_FILENO = 2
Expand Down
22 changes: 22 additions & 0 deletions projects/std/src/process.abra
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,25 @@ func getFunctionNames(): String[] {
_functionNames = Some(functionNames)
functionNames
}

type Stdin {
_buf: Pointer<Byte> = Pointer.malloc(1024)

func readAsString(self): String? {
var nread = libc.read(libc.STDIN_FILENO, self._buf, 1024)
if nread == 0 return None

val str = String.withLength(nread)
str._buffer.copyFrom(self._buf, nread)
return Some(str)
}
}

var _stdin: Stdin? = None
export func stdin(): Stdin {
if _stdin |stdin| return stdin

val stdin = Stdin()
_stdin = Some(stdin)
stdin
}

0 comments on commit 59913dd

Please sign in to comment.