Skip to content

Commit

Permalink
build(git): merged pull request #32 from plume-lang/feat/fun-deps
Browse files Browse the repository at this point in the history
Added support for functional dependencies
  • Loading branch information
thomasvergne authored Aug 4, 2024
2 parents 4f0f55a + fec0530 commit 253cdbd
Show file tree
Hide file tree
Showing 40 changed files with 1,285 additions and 212 deletions.
19 changes: 2 additions & 17 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,10 @@ jobs:
with:
submodules: true

- name: Install CLang on Windows and Ubuntu
uses: KyleMayes/install-llvm-action@v2
if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'ubuntu')
with:
version: "17.0"

- uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
actions-cache-folder: '.xmake-cache'
actions-cache-key: '${{matrix.os}}'

- name: Checking for dependencies
run: |
python3 --version
xmake --version --root
- name: Update xmake repository
run: xmake repo --update --root
node --version
- name: Set up GHC ${{ matrix.ghc-version }}
uses: haskell-actions/setup@v2
Expand Down Expand Up @@ -82,7 +67,7 @@ jobs:
key: ${{ steps.cache.outputs.cache-primary-key }}

- name: Build compiler and VM
run: python3 scripts/build_native.py --root
run: python3 scripts/build_project.py

- name: Create ZIP archive on UNIX
if: startsWith(matrix.os, 'ubuntu') || startsWith(matrix.os, 'macos')
Expand Down
15 changes: 12 additions & 3 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Main where

import Control.Monad.Exception
import Control.Monad.Parser
import Data.Text.IO hiding (putStr)
import Data.Text.IO hiding (putStr, writeFile)
import Plume.Compiler.ClosureConversion.Conversion
import Plume.Compiler.Desugaring.Desugar
import Plume.Compiler.TypeErasure.EraseType
Expand Down Expand Up @@ -55,6 +55,13 @@ main = setEncoding $ do
MkOptions file_input ext_type file_output remove_prelude <- parseOptions
let output = fromMaybe file_input file_output

case ext_type of
"native" -> pure ()
"js" -> pure ()
_ -> do
ppFailure $ "Invalid backend, received: " <> fromString ext_type
exitFailure

env <- lookupEnv "PLUME_PATH"
mod' <- lookupEnv "PPM_PATH"

Expand Down Expand Up @@ -99,9 +106,9 @@ main = setEncoding $ do

let outputPath = output -<.> "js"
writeFileText outputPath code
ppSuccess ("Javacsript code written to " <> fromString outputPath)
ppSuccess ("Javascript code written to " <> fromString outputPath)

_ -> do
"native" -> do
(bytecode, natives', constants) <- runLLIRAssembler desugared
let nativeFuns = getNativeFunctions natives'

Expand All @@ -114,6 +121,8 @@ main = setEncoding $ do
writeFileLBS newPath sbc
ppSuccess ("Bytecode written to " <> fromString newPath)

_ -> ppFailure "Invalid backend"

printBytecode :: [Instruction] -> IO ()
printBytecode bytecode =
mapM_
Expand Down
659 changes: 659 additions & 0 deletions example/basic/hello-world.c

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion example/basic/hello-world.plm
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
fn welcome<A extends to_str>(name: A) {
fn welcome<A extends show>(name: A) {
println("Hello, $name!")
}

println("test")
welcome("world")
welcome(42)
welcome("user")
2 changes: 1 addition & 1 deletion example/iterative/infinite.plm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mut i = 0

while *i < 10000 {
while *i < 100000 {
println("test = $i")

i += 1
Expand Down
14 changes: 14 additions & 0 deletions example/language/conditions.plm
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
x = 5
require "std:io/system"
require "std:io/async-js"

if x == 5 {
println("test")
Expand All @@ -8,3 +10,15 @@ if x == 5 {

nested = if (x == 5) println("test") else println("test2")

wrapped_age: Option<int> = (await input("Enter your age : ")).convert()

switch wrapped_age {
case Some(age) {
if age >= 18 {
println("Majeur")
} else {
println("Mineur")
}
}
case None => println("Pas d'âge")
}
33 changes: 33 additions & 0 deletions example/language/fun-deps.plm
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Functional dependencies help to normalize a relation between two types in
// an extension.
// For instance, the following code would not work if we tried:

interface<Container, Elem> Indexable<Container, Elem> {
fn get_index(container: Container, index: int): Option<Elem>
}

println("Hello, world!"[0])

// because the type of "Hello, world!" is str, and there is no way to infer
// the type of the element of a str from the type of the str itself. In certain
// cases, this could be possible but the compiler deterministically refuses to
// do so.

// Functional dependencies allow us to specify that the type of the element of a
// container can be inferred from the container itself. For instance, we could
// write:

interface<Container, Elem> Indexable<Container, Elem> with Container {
fn get_index(container: Container, index: int): Option<Elem>
}

println("Hello, world!"[0])

// This would work because the compiler can infer that the element of a str is
// char. This is because the compiler knows that the only type that implements
// Indexable<str, char> is str itself.

// The syntax for functional dependencies is "with <Type>" where <Type> is the
// type that the compiler can infer from the other types in the extension. The
// type must be a type parameter of the interface, and it must be a type
// parameter that is not used in the function signature of the interface.
29 changes: 29 additions & 0 deletions scripts/build_scripts/library.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from os import system
from shutil import which
import os.path
from glob import glob
import platform
from sys import argv

PLUME_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))

if (not which('clang')) and (not which('clang-cl')):
print('Please install clang, clang-cl')
exit(1)

args = ['-std=c11', '-Wall', '-Wextra', '-shared']
ffi_files = glob(PLUME_PATH + '/standard/c-ffi/**/*.c', recursive=True)
runtime_headers = PLUME_PATH + '/runtime/include'
runtime_library = [PLUME_PATH + '/runtime/lib/libplume-library.a', 'curl']

output = PLUME_PATH + '/standard/native.plmc'

compiler = 'clang' if which('clang') else 'clang-cl'

res = system(f'{compiler} -I{PLUME_PATH}/runtime/include {PLUME_PATH}/standard/c-ffi/*.c {PLUME_PATH}/runtime/lib/libplume-library.a -lcurl -shared -o {output}')

if res != 0:
print('Failed to compile')
exit(1)

print('Compiled successfully')
34 changes: 34 additions & 0 deletions scripts/build_scripts/vm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from os import system
from shutil import which
import os.path
from glob import glob
import platform
from sys import argv

PLUME_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))

if (not which('clang')) and (not which('clang-cl')):
print('Please install clang, clang-cl')
exit(1)

args = ['-std=c11', '-Wall', '-Wextra', '-shared']
runtime_headers = PLUME_PATH + '/runtime/include'

output = PLUME_PATH + '/runtime/plume-vm.out'
library_output = PLUME_PATH + '/runtime/lib/libplume-library.o'
static_output = PLUME_PATH + '/runtime/lib/libplume-library.a'

compiler = 'clang' if which('clang') else 'clang-cl'

res = system(f'{compiler} -I{PLUME_PATH}/runtime/include {PLUME_PATH}/runtime/src/*.c {PLUME_PATH}/runtime/src/core/*.c -o {output} -g3')

library = system(f'{compiler} -o {library_output} -I{PLUME_PATH}/runtime/include {PLUME_PATH}/runtime/src/*.c {PLUME_PATH}/runtime/src/core/*.c -fPIC')
# static_library = system(f'ar r {static_output} {library_output}')

# print(library, static_library, res)

if res != 0:
print('Failed to compile')
exit(1)

print('Compiled successfully')
14 changes: 0 additions & 14 deletions src/Plume/Compiler/Bytecode/Assembler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,6 @@ instance Assemble LLIR.Instruction where
address' <- negIdx address
pure [BC.LoadLocal address']
Nothing -> error $ "Local " <> name <> " not found"

assemble (LLIR.DropLocal name size) = do
locals <- readIORef localPool
case Map.lookup name locals of
Just address -> do
address' <- negIdx address
pure [BC.DropLocal address' size]
Nothing -> error $ "Local " <> name <> " not found"

assemble (LLIR.DropGlobal name size) = do
globals <- readIORef globalPool
case Map.lookup name globals of
Just address -> pure [BC.DropGlobal address size]
Nothing -> error $ "Global " <> name <> " not found"

assemble (LLIR.StoreLocal name) = do
locals <- readIORef localPool
Expand Down
4 changes: 0 additions & 4 deletions src/Plume/Compiler/Bytecode/Serialize.hs
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ encodeInstruction (MulConst i) =
encodeInstr 40 >> encodeInteger i >> replicateNull 2
encodeInstruction ReturnUnit =
encodeInstr 41 >> replicateNull 3
encodeInstruction (DropLocal i j) =
encodeInstr 42 >> encodeInteger i >> encodeInteger j >> encodeNull
encodeInstruction (DropGlobal i j) =
encodeInstr 43 >> encodeInteger i >> encodeInteger j >> encodeNull

encodeText :: Text -> Put
encodeText w = do
Expand Down
2 changes: 0 additions & 2 deletions src/Plume/Compiler/Bytecode/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ data Instruction
| ListLength
| Halt
| ReturnUnit
| DropGlobal Address Int
| DropLocal Address Int
deriving (Show, Eq)

instance LLIR.Free LLIR.Segment where
Expand Down
Loading

0 comments on commit 253cdbd

Please sign in to comment.