Showing preview only (927K chars total). Download the full file or copy to clipboard to get everything.
Repository: luc-tielen/eclair-lang
Branch: main
Commit: 5254a56ef14e
Files: 183
Total size: 857.3 KB
Directory structure:
gitextract_d5o1d0tz/
├── .dockerignore
├── .ghci
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── build.yml
│ └── ci.yml
├── .gitignore
├── .hlint.yaml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cabal.project
├── cbits/
│ └── semantic_analysis.dl
├── docs/
│ ├── architecture_choices.md
│ └── getting_started.md
├── eclair-lang.cabal
├── hie.yaml
├── lib/
│ ├── Eclair/
│ │ ├── AST/
│ │ │ ├── Analysis.hs
│ │ │ ├── Codegen.hs
│ │ │ ├── IR.hs
│ │ │ ├── Lower.hs
│ │ │ ├── Transforms/
│ │ │ │ ├── ConstantFolding.hs
│ │ │ │ ├── DeadCodeElimination.hs
│ │ │ │ ├── NormalizeRules.hs
│ │ │ │ ├── RemoveAliases.hs
│ │ │ │ └── ReplaceStrings.hs
│ │ │ └── Transforms.hs
│ │ ├── ArgParser.hs
│ │ ├── Common/
│ │ │ ├── Config.hs
│ │ │ ├── Extern.hs
│ │ │ ├── Id.hs
│ │ │ ├── Literal.hs
│ │ │ ├── Location.hs
│ │ │ ├── Operator.hs
│ │ │ └── Pretty.hs
│ │ ├── Comonads.hs
│ │ ├── EIR/
│ │ │ ├── IR.hs
│ │ │ ├── Lower/
│ │ │ │ ├── API.hs
│ │ │ │ ├── Codegen.hs
│ │ │ │ └── Externals.hs
│ │ │ └── Lower.hs
│ │ ├── Error.hs
│ │ ├── JSON.hs
│ │ ├── LLVM/
│ │ │ ├── Allocator/
│ │ │ │ ├── Arena.hs
│ │ │ │ ├── Common.hs
│ │ │ │ ├── Malloc.hs
│ │ │ │ └── Page.hs
│ │ │ ├── BTree/
│ │ │ │ ├── Bounds.hs
│ │ │ │ ├── Compare.hs
│ │ │ │ ├── Create.hs
│ │ │ │ ├── Destroy.hs
│ │ │ │ ├── Find.hs
│ │ │ │ ├── Insert.hs
│ │ │ │ ├── Iterator.hs
│ │ │ │ ├── Size.hs
│ │ │ │ └── Types.hs
│ │ │ ├── BTree.hs
│ │ │ ├── Codegen.hs
│ │ │ ├── Config.hs
│ │ │ ├── Externals.hs
│ │ │ ├── Hash.hs
│ │ │ ├── HashMap.hs
│ │ │ ├── Metadata.hs
│ │ │ ├── Symbol.hs
│ │ │ ├── SymbolTable.hs
│ │ │ ├── Table.hs
│ │ │ ├── Template.hs
│ │ │ └── Vector.hs
│ │ ├── LSP/
│ │ │ ├── Handlers/
│ │ │ │ ├── Diagnostics.hs
│ │ │ │ ├── DocumentHighlight.hs
│ │ │ │ └── Hover.hs
│ │ │ ├── Handlers.hs
│ │ │ ├── JSON.hs
│ │ │ ├── Monad.hs
│ │ │ ├── Types.hs
│ │ │ └── VFS.hs
│ │ ├── LSP.hs
│ │ ├── Parser.hs
│ │ ├── RA/
│ │ │ ├── Codegen.hs
│ │ │ ├── IR.hs
│ │ │ ├── IndexSelection.hs
│ │ │ ├── Lower.hs
│ │ │ ├── Transforms/
│ │ │ │ └── HoistConstraints.hs
│ │ │ └── Transforms.hs
│ │ ├── Souffle/
│ │ │ └── IR.hs
│ │ ├── Transform.hs
│ │ └── TypeSystem.hs
│ ├── Eclair.hs
│ └── Prelude.hs
├── src/
│ └── eclair/
│ └── Main.hs
└── tests/
├── .gitignore
├── ast_transforms/
│ ├── constant_folding.eclair
│ ├── copy_propagation.eclair
│ ├── dead_code_elimination.eclair
│ ├── remove_contradictions.eclair
│ └── shift_assignments.eclair
├── check.sh
├── eclair/
│ ├── Test/
│ │ └── Eclair/
│ │ ├── ArgParserSpec.hs
│ │ ├── JSONSpec.hs
│ │ ├── LLVM/
│ │ │ ├── Allocator/
│ │ │ │ ├── MallocSpec.hs
│ │ │ │ ├── PageSpec.hs
│ │ │ │ └── Utils.hs
│ │ │ ├── BTreeSpec.hs
│ │ │ ├── HashMapSpec.hs
│ │ │ ├── HashSpec.hs
│ │ │ ├── SymbolSpec.hs
│ │ │ ├── SymbolTableSpec.hs
│ │ │ ├── SymbolUtils.hs
│ │ │ └── VectorSpec.hs
│ │ ├── LSP/
│ │ │ ├── HandlersSpec.hs
│ │ │ └── JSONSpec.hs
│ │ └── RA/
│ │ └── IndexSelectionSpec.hs
│ ├── fixtures/
│ │ └── lsp/
│ │ ├── document_highlight.eclair
│ │ ├── hover.eclair
│ │ ├── invalid_syntax.eclair
│ │ ├── semantic_errors.eclair
│ │ ├── type_errors.eclair
│ │ └── unparsable.eclair
│ └── test.hs
├── end_to_end/
│ ├── compile_and_run_native.eclair
│ ├── compile_and_run_wasm.eclair
│ └── compile_and_run_with_extern.eclair
├── hello.eclair
├── lit.cfg
├── lowering/
│ ├── arithmetic.eclair
│ ├── clause_with_same_vars.eclair
│ ├── comparisons.eclair
│ ├── different_types.eclair
│ ├── extern_definitions.eclair
│ ├── multiple_clauses_same_name.eclair
│ ├── multiple_rule_clauses.eclair
│ ├── mutually_recursive_rules.eclair
│ ├── negation.eclair
│ ├── negation_with_wildcards.eclair
│ ├── no_top_level_facts.eclair
│ ├── recursive_mix_of_rules.eclair
│ ├── single_non_recursive_rule.eclair
│ ├── single_recursive_rule.eclair
│ ├── stratification.eclair
│ ├── top_level_facts.eclair
│ └── wasm_codegen.eclair
├── parser/
│ ├── error_recovery.eclair
│ ├── file_not_found.eclair
│ └── valid.eclair
├── runtime/
│ ├── hashmap_test.eclair
│ ├── symbol_table_test.eclair
│ └── vector_test.eclair
├── semantic_analysis/
│ ├── cyclic_negation.eclair
│ ├── dead_internal_relation.eclair
│ ├── invalid_extern_usage.eclair
│ ├── invalid_options_usage.eclair
│ ├── invalid_wildcard_usage.eclair
│ ├── no_output_relations.eclair
│ ├── unconstrained_variables.eclair
│ ├── ungrounded_variables.eclair
│ ├── ungrounded_variables_arithmetic.eclair
│ ├── ungrounded_variables_comparisons.eclair
│ └── ungrounded_variables_negations.eclair
├── string_support/
│ ├── encode_decode_string.eclair
│ ├── encode_decode_string_native.eclair
│ └── encode_decode_string_wasm.eclair
├── transpilation/
│ └── souffle.eclair
├── typesystem/
│ ├── arg_count_mismatch.eclair
│ ├── arithmetic.eclair
│ ├── comparisons.eclair
│ ├── duplicate_type_declarations.eclair
│ ├── extern_definitions.eclair
│ ├── negation.eclair
│ ├── no_rules_for_type.eclair
│ ├── type_mismatch_in_rule.eclair
│ ├── type_mismatch_in_rule_body.eclair
│ ├── type_mismatch_in_rule_head.eclair
│ ├── type_mismatch_top_level_atoms.eclair
│ ├── typed_holes.eclair
│ ├── unification_failure.eclair
│ ├── unknown_atom_in_rule_body.eclair
│ ├── unknown_atom_in_rule_head.eclair
│ ├── unknown_atoms.eclair
│ ├── unknown_top_level_atoms.eclair
│ └── valid.eclair
└── utils/
└── extract_snippet
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
.direnv/
.git/
.github/
dist/
dist-newstyle/
result/
Dockerfile
.dockerignore
.envrc
.ghci
.gitignore
./*.ll
./*.o
./*.a
./*.wasm
./*.eclair
./*.dl
./logo*
hie.yaml
================================================
FILE: .ghci
================================================
:set prompt >
================================================
FILE: .github/FUNDING.yml
================================================
github: luc-tielen
================================================
FILE: .github/workflows/build.yml
================================================
name: "Build"
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- name: Build and test
run: |
set -eo pipefail
export TIMESTAMP=$(date +%s)
docker build -f Dockerfile . -t eclair:$TIMESTAMP | tee eclair-lang-${{matrix.os}}.log
docker run --rm eclair:$TIMESTAMP bash -c "make test" | tee -a eclair-lang-${{matrix.os}}.log
- name: Check for disabled tests
run: |
./tests/check.sh
- name: Upload logs
if: ${{ always() }}
uses: actions/upload-artifact@v3
with:
name: eclair-lang-${{matrix.os}}.log
path: eclair-lang-${{matrix.os}}.log
================================================
FILE: .github/workflows/ci.yml
================================================
name: lint
on:
pull_request:
push:
branches:
- main
- "releases/*"
jobs:
hlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Set up HLint"
uses: rwe/actions-hlint-setup@v1
with:
version: "3.6.1"
- name: "Run HLint"
uses: rwe/actions-hlint-run@v2
with:
path: '["lib/", "src/", "tests/"]'
fail-on: warning
================================================
FILE: .gitignore
================================================
dist-newstyle/
dist/
.direnv/
.devcontainer/
cabal.project.local*
*.ll
*.bc
*.o
*.a
*.s
/*.wasm
/*.dl
/*.eclair
/*.js
result
eclair.prof
eclair.svg
*.eventlog*
eclair.hp
perf.data
perf.data.old
perf.svg
TODO*
================================================
FILE: .hlint.yaml
================================================
# HLint configuration file
# https://github.com/ndmitchell/hlint
##########################
# This file contains a template configuration file, which is typically
# placed as .hlint.yaml in the root of your project
# Specify additional command line arguments
#
# - arguments: [--color, --cpp-simple, -XQuasiQuotes]
# Control which extensions/flags/modules/functions can be used
#
# - extensions:
# - default: false # all extension are banned by default
# - name: [PatternGuards, ViewPatterns] # only these listed extensions can be used
# - {name: CPP, within: CrossPlatform} # CPP can only be used in a given module
#
# - flags:
# - {name: -w, within: []} # -w is allowed nowhere
#
# - modules:
# - {name: [Data.Set, Data.HashSet], as: Set} # if you import Data.Set qualified, it must be as 'Set'
# - {name: Control.Arrow, within: []} # Certain modules are banned entirely
#
# - functions:
# - {name: unsafePerformIO, within: []} # unsafePerformIO can only appear in no modules
- arguments:
- "-XRecursiveDo"
# Add custom hints for this project
#
# Will suggest replacing "wibbleMany [myvar]" with "wibbleOne myvar"
# - error: {lhs: "wibbleMany [x]", rhs: wibbleOne x}
# The hints are named by the string they display in warning messages.
# For example, if you see a warning starting like
#
# Main.hs:116:51: Warning: Redundant ==
#
# You can refer to that hint with `{name: Redundant ==}` (see below).
# Turn on hints that are off by default
#
# Ban "module X(module X) where", to require a real export list
# - warn: {name: Use explicit module export list}
#
# Replace a $ b $ c with a . b $ c
# - group: {name: dollar, enabled: true}
#
# Generalise map to fmap, ++ to <>
# - group: {name: generalise, enabled: true}
# Ignore some builtin hints
# - ignore: {name: Use let}
# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
- ignore: {name: Reduce duplication}
# Define some custom infix operators
# - fixity: infixr 3 ~^#^~
# To generate a suitable file for HLint do:
# $ hlint --default > .hlint.yaml
# Relude-specific (https://github.com/kowainik/relude/blob/main/.hlint.yaml)
- arguments:
- "-XConstraintKinds"
- "-XDeriveGeneric"
- "-XGeneralizedNewtypeDeriving"
- "-XLambdaCase"
- "-XOverloadedStrings"
- "-XRecordWildCards"
- "-XScopedTypeVariables"
- "-XStandaloneDeriving"
- "-XTupleSections"
- "-XTypeApplications"
- "-XViewPatterns"
- ignore:
name: Use head
- ignore:
name: Use Foldable.forM_
- hint:
lhs: "pure ()"
note: "Use 'pass'"
rhs: pass
- hint:
lhs: "return ()"
note: "Use 'pass'"
rhs: pass
- hint:
lhs: "(: [])"
note: "Use `one`"
rhs: one
- hint:
lhs: "(:| [])"
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Sequence.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Text.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Text.Lazy.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.ByteString.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.ByteString.Lazy.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Map.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Map.Strict.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.HashMap.Strict.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.HashMap.Lazy.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.IntMap.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.IntMap.Strict.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.Set.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.HashSet.singleton
note: "Use `one`"
rhs: one
- hint:
lhs: Data.IntSet.singleton
note: "Use `one`"
rhs: one
- warn:
lhs: Control.Exception.evaluate
rhs: evaluateWHNF
- warn:
lhs: "Control.Exception.evaluate (force x)"
rhs: evaluateNF x
- warn:
lhs: "Control.Exception.evaluate (x `deepseq` ())"
rhs: evaluateNF_ x
- warn:
lhs: "void (evaluateWHNF x)"
rhs: evaluateWHNF_ x
- warn:
lhs: "void (evaluateNF x)"
rhs: evaluateNF_ x
- hint:
lhs: Control.Exception.throw
note: "Use 'impureThrow'"
rhs: impureThrow
- warn:
lhs: Data.Text.IO.readFile
rhs: readFileText
- warn:
lhs: Data.Text.IO.writeFile
rhs: writeFileText
- warn:
lhs: Data.Text.IO.appendFile
rhs: appendFileText
- warn:
lhs: Data.Text.Lazy.IO.readFile
rhs: readFileLText
- warn:
lhs: Data.Text.Lazy.IO.writeFile
rhs: writeFileLText
- warn:
lhs: Data.Text.Lazy.IO.appendFile
rhs: appendFileLText
- warn:
lhs: Data.ByteString.readFile
rhs: readFileBS
- warn:
lhs: Data.ByteString.writeFile
rhs: writeFileBS
- warn:
lhs: Data.ByteString.appendFile
rhs: appendFileBS
- warn:
lhs: Data.ByteString.Lazy.readFile
rhs: readFileLBS
- warn:
lhs: Data.ByteString.Lazy.writeFile
rhs: writeFileLBS
- warn:
lhs: Data.ByteString.Lazy.appendFile
rhs: appendFileLBS
- hint:
lhs: "foldl' (flip f)"
note: "Use 'flipfoldl''"
rhs: "flipfoldl' f"
- warn:
lhs: "foldl' (+) 0"
rhs: sum
- warn:
lhs: "foldl' (*) 1"
rhs: product
- hint:
lhs: "fmap and (sequence s)"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: andM s
- hint:
lhs: "and <$> sequence s"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: andM s
- hint:
lhs: "fmap or (sequence s)"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: orM s
- hint:
lhs: "or <$> sequence s"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: orM s
- hint:
lhs: "fmap and (mapM f s)"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: allM f s
- hint:
lhs: "and <$> mapM f s"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: allM f s
- hint:
lhs: "fmap or (mapM f s)"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: anyM f s
- hint:
lhs: "or <$> mapM f s"
note: Applying this hint would mean that some actions that were being executed previously would no longer be executed.
rhs: anyM f s
- warn:
lhs: "getAlt (foldMap (Alt . f) xs)"
rhs: asumMap xs
- warn:
lhs: "getAlt . foldMap (Alt . f)"
rhs: asumMap
- hint:
lhs: "foldr (\\x acc -> f x <|> acc) empty"
note: "Use 'asumMap'"
rhs: asumMap f
- hint:
lhs: "asum (map f xs)"
note: "Use 'asumMap'"
rhs: asumMap f xs
- warn:
lhs: "map fst &&& map snd"
rhs: unzip
- hint:
lhs: "fmap (fmap f) x"
note: "Use '(<<$>>)'"
rhs: "f <<$>> x"
- hint:
lhs: "(\\f -> f x) <$> ff"
note: Use flap operator
rhs: "ff ?? x"
- hint:
lhs: "fmap (\\f -> f x) ff"
note: Use flap operator
rhs: "ff ?? x"
- hint:
lhs: "fmap ($ x) ff"
note: Use flap operator
rhs: "ff ?? x"
- hint:
lhs: "($ x) <$> ff"
note: Use flap operator
rhs: "ff ?? x"
- warn:
lhs: "fmap f (nonEmpty x)"
rhs: viaNonEmpty f x
- warn:
lhs: fmap f . nonEmpty
rhs: viaNonEmpty f
- warn:
lhs: "f <$> nonEmpty x"
rhs: viaNonEmpty f x
- warn:
lhs: partitionEithers . map f
rhs: partitionWith f
- warn:
lhs: partitionEithers $ map f x
rhs: partitionWith f x
- warn:
lhs: "f >>= guard"
rhs: guardM f
- warn:
lhs: guard =<< f
rhs: guardM f
- warn:
lhs: forever
note: "'forever' is loosely typed and may hide errors"
rhs: infinitely
- warn:
lhs: "whenM (not <$> x)"
rhs: unlessM x
- warn:
lhs: "unlessM (not <$> x)"
rhs: whenM x
- warn:
lhs: "either (const True) (const False)"
rhs: isLeft
- warn:
lhs: "either (const False) (const True)"
rhs: isRight
- warn:
lhs: "either id (const a)"
rhs: fromLeft a
- warn:
lhs: "either (const b) id"
rhs: fromRight b
- warn:
lhs: "either Just (const Nothing)"
rhs: leftToMaybe
- warn:
lhs: "either (const Nothing) Just"
rhs: rightToMaybe
- warn:
lhs: "maybe (Left l) Right"
rhs: maybeToRight l
- warn:
lhs: "maybe (Right r) Left"
rhs: maybeToLeft r
- warn:
lhs: "case m of Just x -> f x; Nothing -> pure ()"
rhs: whenJust m f
- warn:
lhs: "case m of Just x -> f x; Nothing -> return ()"
rhs: whenJust m f
- warn:
lhs: "case m of Just x -> f x; Nothing -> pass"
rhs: whenJust m f
- warn:
lhs: "case m of Nothing -> pure () ; Just x -> f x"
rhs: whenJust m f
- warn:
lhs: "case m of Nothing -> return (); Just x -> f x"
rhs: whenJust m f
- warn:
lhs: "case m of Nothing -> pass ; Just x -> f x"
rhs: whenJust m f
- warn:
lhs: "maybe (pure ()) f m"
rhs: whenJust m f
- warn:
lhs: "maybe (return ()) f m"
rhs: whenJust m f
- warn:
lhs: maybe pass f m
rhs: whenJust m f
- warn:
lhs: "m >>= \\a -> whenJust a f"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Just x -> f x; Nothing -> pure ()"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Just x -> f x; Nothing -> return ()"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Just x -> f x; Nothing -> pass"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Nothing -> pure () ; Just x -> f x"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Nothing -> return (); Just x -> f x"
rhs: whenJustM m f
- warn:
lhs: "m >>= \\case Nothing -> pass ; Just x -> f x"
rhs: whenJustM m f
- warn:
lhs: "maybe (pure ()) f =<< m"
rhs: whenJustM m f
- warn:
lhs: "maybe (return ()) f =<< m"
rhs: whenJustM m f
- warn:
lhs: maybe pass f =<< m
rhs: whenJustM m f
- warn:
lhs: "m >>= maybe (pure ()) f"
rhs: whenJustM m f
- warn:
lhs: "m >>= maybe (return ()) f"
rhs: whenJustM m f
- warn:
lhs: "m >>= maybe pass f"
rhs: whenJustM m f
- warn:
lhs: "case m of Just _ -> pure () ; Nothing -> x"
rhs: whenNothing_ m x
- warn:
lhs: "case m of Just _ -> return (); Nothing -> x"
rhs: whenNothing_ m x
- warn:
lhs: "case m of Just _ -> pass ; Nothing -> x"
rhs: whenNothing_ m x
- warn:
lhs: "case m of Nothing -> x; Just _ -> pure ()"
rhs: whenNothing_ m x
- warn:
lhs: "case m of Nothing -> x; Just _ -> return ()"
rhs: whenNothing_ m x
- warn:
lhs: "case m of Nothing -> x; Just _ -> pass"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (\\_ -> pure () ) m"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (\\_ -> return () ) m"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (\\_ -> pass ) m"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (const (pure () )) m"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (const (return ())) m"
rhs: whenNothing_ m x
- warn:
lhs: "maybe x (const pass) m"
rhs: whenNothing_ m x
- warn:
lhs: "m >>= \\a -> whenNothing_ a x"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Just _ -> pure () ; Nothing -> x"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Just _ -> return (); Nothing -> x"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Just _ -> pass ; Nothing -> x"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Nothing -> x; Just _ -> pure ()"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Nothing -> x; Just _ -> return ()"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= \\case Nothing -> x; Just _ -> pass"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (\\_ -> pure () ) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (\\_ -> return () ) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (\\_ -> pass ) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (const (pure () )) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (const (return ())) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "maybe x (const pass) =<< m"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (\\_ -> pure ())"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (\\_ -> return ())"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (\\_ -> pass)"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (const (pure ()) )"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (const (return ()))"
rhs: whenNothingM_ m x
- warn:
lhs: "m >>= maybe x (const pass)"
rhs: whenNothingM_ m x
- warn:
lhs: "whenLeft ()"
rhs: whenLeft_
- warn:
lhs: "case m of Left x -> f x; Right _ -> pure ()"
rhs: whenLeft_ m f
- warn:
lhs: "case m of Left x -> f x; Right _ -> return ()"
rhs: whenLeft_ m f
- warn:
lhs: "case m of Left x -> f x; Right _ -> pass"
rhs: whenLeft_ m f
- warn:
lhs: "case m of Right _ -> pure () ; Left x -> f x"
rhs: whenLeft_ m f
- warn:
lhs: "case m of Right _ -> return (); Left x -> f x"
rhs: whenLeft_ m f
- warn:
lhs: "case m of Right _ -> pass ; Left x -> f x"
rhs: whenLeft_ m f
- warn:
lhs: "either f (\\_ -> pure () ) m"
rhs: whenLeft_ m f
- warn:
lhs: "either f (\\_ -> return () ) m"
rhs: whenLeft_ m f
- warn:
lhs: "either f (\\_ -> pass ) m"
rhs: whenLeft_ m f
- warn:
lhs: "either f (const (pure () )) m"
rhs: whenLeft_ m f
- warn:
lhs: "either f (const (return ())) m"
rhs: whenLeft_ m f
- warn:
lhs: "either f (const pass) m"
rhs: whenLeft_ m f
- warn:
lhs: "m >>= \\a -> whenLeft_ a f"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Left x -> f x; Right _ -> pure ()"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Left x -> f x; Right _ -> return ()"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Left x -> f x; Right _ -> pass"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Right _ -> pure () ; Left x -> f x"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Right _ -> return (); Left x -> f x"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= \\case Right _ -> pass ; Left x -> f x"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (\\_ -> pure () ) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (\\_ -> return () ) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (\\_ -> pass ) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (const (pure () )) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (const (return ())) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "either f (const pass) =<< m"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (\\_ -> pure ())"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (\\_ -> return ())"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (\\_ -> pass)"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (const (pure ()) )"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (const (return ()))"
rhs: whenLeftM_ m f
- warn:
lhs: "m >>= either f (const pass)"
rhs: whenLeftM_ m f
- warn:
lhs: "whenRight ()"
rhs: whenRight_
- warn:
lhs: "case m of Right x -> f x; Left _ -> pure ()"
rhs: whenRight_ m f
- warn:
lhs: "case m of Right x -> f x; Left _ -> return ()"
rhs: whenRight_ m f
- warn:
lhs: "case m of Right x -> f x; Left _ -> pass"
rhs: whenRight_ m f
- warn:
lhs: "case m of Left _ -> pure () ; Right x -> f x"
rhs: whenRight_ m f
- warn:
lhs: "case m of Left _ -> return (); Right x -> f x"
rhs: whenRight_ m f
- warn:
lhs: "case m of Left _ -> pass ; Right x -> f x"
rhs: whenRight_ m f
- warn:
lhs: "either (\\_ -> pure () ) f m"
rhs: whenRight_ m f
- warn:
lhs: "either (\\_ -> return () ) f m"
rhs: whenRight_ m f
- warn:
lhs: "either (\\_ -> pass ) f m"
rhs: whenRight_ m f
- warn:
lhs: "either (const (pure () )) f m"
rhs: whenRight_ m f
- warn:
lhs: "either (const (return ())) f m"
rhs: whenRight_ m f
- warn:
lhs: "either (const pass) f m"
rhs: whenRight_ m f
- warn:
lhs: "m >>= \\a -> whenRight_ a f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Right x -> f x; Left _ -> pure () "
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Right x -> f x; Left _ -> return ()"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Right x -> f x; Left _ -> pass"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Left _ -> pure () ; Right x -> f x"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Left _ -> return (); Right x -> f x"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= \\case Left _ -> pass ; Right x -> f x"
rhs: whenRightM_ m f
- warn:
lhs: "either (\\_ -> pure () ) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "either (\\_ -> return () ) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "either (\\_ -> pass ) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "either (const (pure () )) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "either (const (return ())) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "either (const pass) f =<< m"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (\\_ -> pure ()) f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (\\_ -> return ()) f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (\\_ -> pass) f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (const (pure ()) ) f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (const (return ())) f"
rhs: whenRightM_ m f
- warn:
lhs: "m >>= either (const pass) f"
rhs: whenRightM_ m f
- warn:
lhs: "case m of Left x -> f x; Right _ -> pure d "
rhs: whenLeft d m f
- warn:
lhs: "case m of Left x -> f x; Right _ -> return d"
rhs: whenLeft d m f
- warn:
lhs: "case m of Right _ -> pure d ; Left x -> f x"
rhs: whenLeft d m f
- warn:
lhs: "case m of Right _ -> return d; Left x -> f x"
rhs: whenLeft d m f
- warn:
lhs: "either f (\\_ -> pure d ) m"
rhs: whenLeft d m f
- warn:
lhs: "either f (\\_ -> return d ) m"
rhs: whenLeft d m f
- warn:
lhs: "either f (const (pure d )) m"
rhs: whenLeft d m f
- warn:
lhs: "either f (const (return d)) m"
rhs: whenLeft d m f
- warn:
lhs: "m >>= \\a -> whenLeft d a f"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= \\case Left x -> f x; Right _ -> pure d"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= \\case Left x -> f x; Right _ -> return d"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= \\case Right _ -> pure d ; Left x -> f x"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= \\case Right _ -> return d; Left x -> f x"
rhs: whenLeftM d m f
- warn:
lhs: "either f (\\_ -> pure d ) =<< m"
rhs: whenLeftM d m f
- warn:
lhs: "either f (\\_ -> return d ) =<< m"
rhs: whenLeftM d m f
- warn:
lhs: "either f (const (pure d )) =<< m"
rhs: whenLeftM d m f
- warn:
lhs: "either f (const (return d)) =<< m"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= either f (\\_ -> pure d)"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= either f (\\_ -> return d)"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= either f (const (pure d))"
rhs: whenLeftM d m f
- warn:
lhs: "m >>= either f (const (return d))"
rhs: whenLeftM d m f
- warn:
lhs: "case m of Right x -> f x; Left _ -> pure d"
rhs: whenRight d m f
- warn:
lhs: "case m of Right x -> f x; Left _ -> return d"
rhs: whenRight d m f
- warn:
lhs: "case m of Left _ -> pure d ; Right x -> f x"
rhs: whenRight d m f
- warn:
lhs: "case m of Left _ -> return d; Right x -> f x"
rhs: whenRight d m f
- warn:
lhs: "either (\\_ -> pure d ) f m"
rhs: whenRight d m f
- warn:
lhs: "either (\\_ -> return d ) f m"
rhs: whenRight d m f
- warn:
lhs: "either (const (pure d )) f m"
rhs: whenRight d m f
- warn:
lhs: "either (const (return d)) f m"
rhs: whenRight d m f
- warn:
lhs: "m >>= \\a -> whenRight d a f"
rhs: whenRightM d m f
- warn:
lhs: "m >>= \\case Right x -> f x; Left _ -> pure d"
rhs: whenRightM d m f
- warn:
lhs: "m >>= \\case Right x -> f x; Left _ -> return d"
rhs: whenRightM d m f
- warn:
lhs: "m >>= \\case Left _ -> pure d ; Right x -> f x"
rhs: whenRightM d m f
- warn:
lhs: "m >>= \\case Left _ -> return d; Right x -> f x"
rhs: whenRightM d m f
- warn:
lhs: "either (\\_ -> pure d ) f =<< m"
rhs: whenRightM d m f
- warn:
lhs: "either (\\_ -> return d ) f =<< m"
rhs: whenRightM d m f
- warn:
lhs: "either (const (pure d )) f =<< m"
rhs: whenRightM d m f
- warn:
lhs: "either (const (return d)) f =<< m"
rhs: whenRightM d m f
- warn:
lhs: "m >>= either (\\_ -> pure d) f"
rhs: whenRightM d m f
- warn:
lhs: "m >>= either (\\_ -> return d) f"
rhs: whenRightM d m f
- warn:
lhs: "m >>= either (const (pure d) ) f"
rhs: whenRightM d m f
- warn:
lhs: "m >>= either (const (return d)) f"
rhs: whenRightM d m f
- warn:
lhs: "case m of [] -> return (); (x:xs) -> f (x :| xs)"
rhs: whenNotNull m f
- warn:
lhs: "case m of [] -> pure () ; (x:xs) -> f (x :| xs)"
rhs: whenNotNull m f
- warn:
lhs: "case m of [] -> pass ; (x:xs) -> f (x :| xs)"
rhs: whenNotNull m f
- warn:
lhs: "case m of (x:xs) -> f (x :| xs); [] -> return ()"
rhs: whenNotNull m f
- warn:
lhs: "case m of (x:xs) -> f (x :| xs); [] -> pure () "
rhs: whenNotNull m f
- warn:
lhs: "case m of (x:xs) -> f (x :| xs); [] -> pass "
rhs: whenNotNull m f
- warn:
lhs: "m >>= \\case [] -> pass ; (x:xs) -> f (x :| xs)"
rhs: whenNotNullM m f
- warn:
lhs: "m >>= \\case [] -> pure () ; (x:xs) -> f (x :| xs)"
rhs: whenNotNullM m f
- warn:
lhs: "m >>= \\case [] -> return (); (x:xs) -> f (x :| xs)"
rhs: whenNotNullM m f
- warn:
lhs: "m >>= \\case (x:xs) -> f (x :| xs); [] -> pass "
rhs: whenNotNullM m f
- warn:
lhs: "m >>= \\case (x:xs) -> f (x :| xs); [] -> pure () "
rhs: whenNotNullM m f
- warn:
lhs: "m >>= \\case (x:xs) -> f (x :| xs); [] -> return ()"
rhs: whenNotNullM m f
- warn:
lhs: mapMaybe leftToMaybe
rhs: lefts
- warn:
lhs: mapMaybe rightToMaybe
rhs: rights
- warn:
lhs: flip runReaderT
rhs: usingReaderT
- warn:
lhs: flip runReader
rhs: usingReader
- warn:
lhs: flip runStateT
rhs: usingStateT
- warn:
lhs: flip runState
rhs: usingState
- warn:
lhs: "fst <$> usingStateT s st"
rhs: evaluatingStateT s st
- warn:
lhs: "fst (usingState s st)"
rhs: evaluatingState s st
- warn:
lhs: "snd <$> usingStateT s st"
rhs: executingStateT s st
- warn:
lhs: "snd (usingState s st)"
rhs: executingState s st
- warn:
lhs: "MaybeT (pure m)"
rhs: hoistMaybe m
- warn:
lhs: "MaybeT (return m)"
rhs: hoistMaybe m
- warn:
lhs: MaybeT . pure
rhs: hoistMaybe
- warn:
lhs: MaybeT . return
rhs: hoistMaybe
- warn:
lhs: "ExceptT (pure m)"
rhs: hoistEither m
- warn:
lhs: "ExceptT (return m)"
rhs: hoistEither m
- warn:
lhs: ExceptT . pure
rhs: hoistEither
- warn:
lhs: ExceptT . return
rhs: hoistEither
- warn:
lhs: fromMaybe mempty
rhs: maybeToMonoid
- warn:
lhs: "m ?: mempty"
rhs: maybeToMonoid m
- warn:
lhs: "Data.Map.toAscList (Data.Map.fromList x)"
rhs: sortWith fst x
- warn:
lhs: "Data.Map.toDescList (Data.Map.fromList x)"
rhs: "sortWith (Down . fst) x"
- warn:
lhs: "Data.Set.toList (Data.Set.fromList l)"
rhs: sortNub l
- warn:
lhs: "Data.Set.assocs (Data.Set.fromList l)"
rhs: sortNub l
- warn:
lhs: "Data.Set.toAscList (Data.Set.fromList l)"
rhs: sortNub l
- warn:
lhs: "Data.HashSet.toList (Data.HashSet.fromList l)"
rhs: unstableNub l
- warn:
lhs: nub
note: "'nub' is O(n^2), 'ordNub' is O(n log n)"
rhs: ordNub
- warn:
lhs: "sortBy (comparing f)"
note: "If the function you are using for 'comparing' is slow, use 'sortOn' instead of 'sortWith', because 'sortOn' caches applications the function and 'sortWith' doesn't."
rhs: sortWith f
- warn:
lhs: sortOn fst
note: "'sortWith' will be faster here because it doesn't do caching"
rhs: sortWith fst
- warn:
lhs: sortOn snd
note: "'sortWith' will be faster here because it doesn't do caching"
rhs: sortWith snd
- warn:
lhs: "sortOn (Down . fst)"
note: "'sortWith' will be faster here because it doesn't do caching"
rhs: "sortWith (Down . fst)"
- warn:
lhs: "sortOn (Down . snd)"
note: "'sortWith' will be faster here because it doesn't do caching"
rhs: "sortWith (Down . snd)"
- warn:
lhs: Data.Text.IO.putStr
rhs: putText
- warn:
lhs: Data.Text.IO.putStrLn
rhs: putTextLn
- warn:
lhs: Data.Text.Lazy.IO.putStr
rhs: putLText
- warn:
lhs: Data.Text.Lazy.IO.putStrLn
rhs: putLTextLn
- warn:
lhs: Data.ByteString.Char8.putStr
rhs: putBS
- warn:
lhs: Data.ByteString.Char8.putStrLn
rhs: putBSLn
- warn:
lhs: Data.ByteString.Lazy.Char8.putStr
rhs: putLBS
- warn:
lhs: Data.ByteString.Lazy.Char8.putStrLn
rhs: putLBSLn
- warn:
lhs: Data.Text.Lazy.Text
rhs: LText
- warn:
lhs: Data.ByteString.Lazy.ByteString
rhs: LByteString
- warn:
lhs: Data.ByteString.UTF8.fromString
rhs: encodeUtf8
- warn:
lhs: Data.ByteString.UTF8.toString
rhs: decodeUtf8
- warn:
lhs: Data.Text.Encoding.encodeUtf8
rhs: encodeUtf8
- warn:
lhs: Data.Text.Encoding.decodeUtf8
rhs: decodeUtf8
- warn:
lhs: "Data.ByteString.Lazy.toStrict (encodeUtf8 x)"
rhs: encodeUtf8 x
- warn:
lhs: "toStrict (encodeUtf8 x)"
rhs: encodeUtf8 x
- warn:
lhs: "decodeUtf8 (Data.ByteString.Lazy.fromStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: "decodeUtf8 (fromStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: Data.ByteString.Lazy.UTF8.fromString
rhs: encodeUtf8
- warn:
lhs: Data.ByteString.Lazy.UTF8.toString
rhs: decodeUtf8
- warn:
lhs: "Data.ByteString.Lazy.fromStrict (Data.Text.Encoding.encodeUtf8 x)"
rhs: encodeUtf8 x
- warn:
lhs: "Data.ByteString.Lazy.fromStrict (encodeUtf8 x)"
rhs: encodeUtf8 x
- warn:
lhs: "Data.Text.Encoding.decodeUtf8 (Data.ByteString.Lazy.toStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: "Data.Text.Encoding.decodeUtf8 (toStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: "decodeUtf8 (Data.ByteString.Lazy.toStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: "decodeUtf8 (toStrict x)"
rhs: decodeUtf8 x
- warn:
lhs: Data.Text.pack
rhs: toText
- warn:
lhs: Data.Text.unpack
rhs: toString
- warn:
lhs: Data.Text.Lazy.pack
rhs: toLText
- warn:
lhs: Data.Text.Lazy.unpack
rhs: toString
- warn:
lhs: Data.Text.Lazy.toStrict
rhs: toText
- warn:
lhs: Data.Text.Lazy.fromStrict
rhs: toLText
- warn:
lhs: "Data.Text.pack (show x)"
rhs: show x
- warn:
lhs: "Data.Text.Lazy.pack (show x)"
rhs: show x
- warn:
lhs: Data.ByteString.Lazy.fromStrict
rhs: fromStrict
- warn:
lhs: Data.ByteString.Lazy.toStrict
rhs: toStrict
- warn:
lhs: Data.Text.Lazy.fromStrict
rhs: fromStrict
- warn:
lhs: Data.Text.Lazy.toStrict
rhs: toStrict
- warn:
lhs: Control.Applicative.Alternative
name: "Use 'Alternative' from Relude"
note: "'Alternative' is already exported from Relude"
rhs: Alternative
- warn:
lhs: Control.Applicative.empty
name: "Use 'empty' from Relude"
note: "'empty' is already exported from Relude"
rhs: empty
- warn:
lhs: "(Control.Applicative.<|>)"
name: "Use '<|>' from Relude"
note: "Operator '(<|>)' is already exported from Relude"
rhs: "(<|>)"
- warn:
lhs: Control.Applicative.some
name: "Use 'some' from Relude"
note: "'some' is already exported from Relude"
rhs: some
- warn:
lhs: Control.Applicative.many
name: "Use 'many' from Relude"
note: "'many' is already exported from Relude"
rhs: many
- warn:
lhs: Control.Applicative.Const
name: "Use 'Const' from Relude"
note: "'Const' is already exported from Relude"
rhs: Const
- warn:
lhs: Control.Applicative.getConst
name: "Use 'getConst' from Relude"
note: "'getConst' is already exported from Relude"
rhs: getConst
- warn:
lhs: Control.Applicative.ZipList
name: "Use 'ZipList' from Relude"
note: "'ZipList' is already exported from Relude"
rhs: ZipList
- warn:
lhs: Control.Applicative.getZipList
name: "Use 'getZipList' from Relude"
note: "'getZipList' is already exported from Relude"
rhs: getZipList
- warn:
lhs: Control.Applicative.liftA2
name: "Use 'liftA2' from Relude"
note: "'liftA2' is already exported from Relude"
rhs: liftA2
- warn:
lhs: Control.Applicative.liftA3
name: "Use 'liftA3' from Relude"
note: "'liftA3' is already exported from Relude"
rhs: liftA3
- warn:
lhs: Control.Applicative.optional
name: "Use 'optional' from Relude"
note: "'optional' is already exported from Relude"
rhs: optional
- warn:
lhs: "(Control.Applicative.<**>)"
name: "Use '<**>' from Relude"
note: "Operator '(<**>)' is already exported from Relude"
rhs: "(<**>)"
- warn:
lhs: Data.Bits.xor
name: "Use 'xor' from Relude"
note: "'xor' is already exported from Relude"
rhs: xor
- warn:
lhs: Data.Char.chr
name: "Use 'chr' from Relude"
note: "'chr' is already exported from Relude"
rhs: chr
- warn:
lhs: Data.Int.Int8
name: "Use 'Int8' from Relude"
note: "'Int8' is already exported from Relude"
rhs: Int8
- warn:
lhs: Data.Int.Int16
name: "Use 'Int16' from Relude"
note: "'Int16' is already exported from Relude"
rhs: Int16
- warn:
lhs: Data.Int.Int32
name: "Use 'Int32' from Relude"
note: "'Int32' is already exported from Relude"
rhs: Int32
- warn:
lhs: Data.Int.Int64
name: "Use 'Int64' from Relude"
note: "'Int64' is already exported from Relude"
rhs: Int64
- warn:
lhs: Data.Word.Word8
name: "Use 'Word8' from Relude"
note: "'Word8' is already exported from Relude"
rhs: Word8
- warn:
lhs: Data.Word.Word16
name: "Use 'Word16' from Relude"
note: "'Word16' is already exported from Relude"
rhs: Word16
- warn:
lhs: Data.Word.Word32
name: "Use 'Word32' from Relude"
note: "'Word32' is already exported from Relude"
rhs: Word32
- warn:
lhs: Data.Word.Word64
name: "Use 'Word64' from Relude"
note: "'Word64' is already exported from Relude"
rhs: Word64
- warn:
lhs: Data.Word.byteSwap16
name: "Use 'byteSwap16' from Relude"
note: "'byteSwap16' is already exported from Relude"
rhs: byteSwap16
- warn:
lhs: Data.Word.byteSwap32
name: "Use 'byteSwap32' from Relude"
note: "'byteSwap32' is already exported from Relude"
rhs: byteSwap32
- warn:
lhs: Data.Word.byteSwap64
name: "Use 'byteSwap64' from Relude"
note: "'byteSwap64' is already exported from Relude"
rhs: byteSwap64
- warn:
lhs: Numeric.Natural.Natural
name: "Use 'Natural' from Relude"
note: "'Natural' is already exported from Relude"
rhs: Natural
- warn:
lhs: System.IO.IOMode
name: "Use 'IOMode' from Relude"
note: "'IOMode' is already exported from Relude"
rhs: IOMode
- warn:
lhs: System.IO.ReadMode
name: "Use 'ReadMode' from Relude"
note: "'ReadMode' is already exported from Relude"
rhs: ReadMode
- warn:
lhs: System.IO.WriteMode
name: "Use 'WriteMode' from Relude"
note: "'WriteMode' is already exported from Relude"
rhs: WriteMode
- warn:
lhs: System.IO.AppendMode
name: "Use 'AppendMode' from Relude"
note: "'AppendMode' is already exported from Relude"
rhs: AppendMode
- warn:
lhs: System.IO.ReadWriteMode
name: "Use 'ReadWriteMode' from Relude"
note: "'ReadWriteMode' is already exported from Relude"
rhs: ReadWriteMode
- warn:
lhs: Data.Ord.Down
name: "Use 'Down' from Relude"
note: "'Down' is already exported from Relude"
rhs: Down
- warn:
lhs: Data.Ord.comparing
name: "Use 'comparing' from Relude"
note: "'comparing' is already exported from Relude"
rhs: comparing
- warn:
lhs: Data.Coerce.Coercible
name: "Use 'Coercible' from Relude"
note: "'Coercible' is already exported from Relude"
rhs: Coercible
- warn:
lhs: Data.Coerce.coerce
name: "Use 'coerce' from Relude"
note: "'coerce' is already exported from Relude"
rhs: coerce
- warn:
lhs: Data.Kind.Constraint
name: "Use 'Constraint' from Relude"
note: "'Constraint' is already exported from Relude"
rhs: Constraint
- warn:
lhs: Data.Kind.Type
name: "Use 'Type' from Relude"
note: "'Type' is already exported from Relude"
rhs: Type
- warn:
lhs: Data.Typeable.Typeable
name: "Use 'Typeable' from Relude"
note: "'Typeable' is already exported from Relude"
rhs: Typeable
- warn:
lhs: Data.Proxy.Proxy
name: "Use 'Proxy' from Relude"
note: "'Proxy' is already exported from Relude"
rhs: Proxy
- warn:
lhs: Data.Typeable.Typeable
name: "Use 'Typeable' from Relude"
note: "'Typeable' is already exported from Relude"
rhs: Typeable
- warn:
lhs: Data.Void.Void
name: "Use 'Void' from Relude"
note: "'Void' is already exported from Relude"
rhs: Void
- warn:
lhs: Data.Void.absurd
name: "Use 'absurd' from Relude"
note: "'absurd' is already exported from Relude"
rhs: absurd
- warn:
lhs: Data.Void.vacuous
name: "Use 'vacuous' from Relude"
note: "'vacuous' is already exported from Relude"
rhs: vacuous
- warn:
lhs: Data.Base.maxInt
name: "Use 'maxInt' from Relude"
note: "'maxInt' is already exported from Relude"
rhs: maxInt
- warn:
lhs: Data.Base.minInt
name: "Use 'minInt' from Relude"
note: "'minInt' is already exported from Relude"
rhs: minInt
- warn:
lhs: Data.Base.ord
name: "Use 'ord' from Relude"
note: "'ord' is already exported from Relude"
rhs: ord
- warn:
lhs: GHC.Enum.boundedEnumFrom
name: "Use 'boundedEnumFrom' from Relude"
note: "'boundedEnumFrom' is already exported from Relude"
rhs: boundedEnumFrom
- warn:
lhs: GHC.Enum.boundedEnumFromThen
name: "Use 'boundedEnumFromThen' from Relude"
note: "'boundedEnumFromThen' is already exported from Relude"
rhs: boundedEnumFromThen
- warn:
lhs: GHC.Generics.Generic
name: "Use 'Generic' from Relude"
note: "'Generic' is already exported from Relude"
rhs: Generic
- warn:
lhs: GHC.Real.Ratio
name: "Use 'Ratio' from Relude"
note: "'Ratio' is already exported from Relude"
rhs: Ratio
- warn:
lhs: GHC.Real.Rational
name: "Use 'Rational' from Relude"
note: "'Rational' is already exported from Relude"
rhs: Rational
- warn:
lhs: GHC.Real.denominator
name: "Use 'denominator' from Relude"
note: "'denominator' is already exported from Relude"
rhs: denominator
- warn:
lhs: GHC.Real.numerator
name: "Use 'numerator' from Relude"
note: "'numerator' is already exported from Relude"
rhs: numerator
- warn:
lhs: GHC.TypeNats.CmpNat
name: "Use 'CmpNat' from Relude"
note: "'CmpNat' is already exported from Relude"
rhs: CmpNat
- warn:
lhs: GHC.TypeNats.KnownNat
name: "Use 'KnownNat' from Relude"
note: "'KnownNat' is already exported from Relude"
rhs: KnownNat
- warn:
lhs: GHC.TypeNats.Nat
name: "Use 'Nat' from Relude"
note: "'Nat' is already exported from Relude"
rhs: Nat
- warn:
lhs: GHC.TypeNats.SomeNat
name: "Use 'SomeNat' from Relude"
note: "'SomeNat' is already exported from Relude"
rhs: SomeNat
- warn:
lhs: GHC.TypeNats.natVal
name: "Use 'natVal' from Relude"
note: "'natVal' is already exported from Relude"
rhs: natVal
- warn:
lhs: GHC.TypeNats.someNatVal
name: "Use 'someNatVal' from Relude"
note: "'someNatVal' is already exported from Relude"
rhs: someNatVal
- warn:
lhs: GHC.TypeLits.CmpNat
name: "Use 'CmpNat' from Relude"
note: "'CmpNat' is already exported from Relude"
rhs: CmpNat
- warn:
lhs: GHC.TypeLits.KnownNat
name: "Use 'KnownNat' from Relude"
note: "'KnownNat' is already exported from Relude"
rhs: KnownNat
- warn:
lhs: GHC.TypeLits.Nat
name: "Use 'Nat' from Relude"
note: "'Nat' is already exported from Relude"
rhs: Nat
- warn:
lhs: GHC.TypeLits.SomeNat
name: "Use 'SomeNat' from Relude"
note: "'SomeNat' is already exported from Relude"
rhs: SomeNat
- warn:
lhs: GHC.TypeLits.natVal
name: "Use 'natVal' from Relude"
note: "'natVal' is already exported from Relude"
rhs: natVal
- warn:
lhs: GHC.TypeLits.someNatVal
name: "Use 'someNatVal' from Relude"
note: "'someNatVal' is already exported from Relude"
rhs: someNatVal
- warn:
lhs: GHC.ExecutionStack.getStackTrace
name: "Use 'getStackTrace' from Relude"
note: "'getStackTrace' is already exported from Relude"
rhs: getStackTrace
- warn:
lhs: GHC.ExecutionStack.showStackTrace
name: "Use 'showStackTrace' from Relude"
note: "'showStackTrace' is already exported from Relude"
rhs: showStackTrace
- warn:
lhs: GHC.OverloadedLabels.IsLabel
name: "Use 'IsLabel' from Relude"
note: "'IsLabel' is already exported from Relude"
rhs: IsLabel
- warn:
lhs: GHC.OverloadedLabels.fromLabel
name: "Use 'fromLabel' from Relude"
note: "'fromLabel' is already exported from Relude"
rhs: fromLabel
- warn:
lhs: GHC.Stack.CallStack
name: "Use 'CallStack' from Relude"
note: "'CallStack' is already exported from Relude"
rhs: CallStack
- warn:
lhs: GHC.Stack.HasCallStack
name: "Use 'HasCallStack' from Relude"
note: "'HasCallStack' is already exported from Relude"
rhs: HasCallStack
- warn:
lhs: GHC.Stack.callStack
name: "Use 'callStack' from Relude"
note: "'callStack' is already exported from Relude"
rhs: callStack
- warn:
lhs: GHC.Stack.currentCallStack
name: "Use 'currentCallStack' from Relude"
note: "'currentCallStack' is already exported from Relude"
rhs: currentCallStack
- warn:
lhs: GHC.Stack.getCallStack
name: "Use 'getCallStack' from Relude"
note: "'getCallStack' is already exported from Relude"
rhs: getCallStack
- warn:
lhs: GHC.Stack.prettyCallStack
name: "Use 'prettyCallStack' from Relude"
note: "'prettyCallStack' is already exported from Relude"
rhs: prettyCallStack
- warn:
lhs: GHC.Stack.prettySrcLoc
name: "Use 'prettySrcLoc' from Relude"
note: "'prettySrcLoc' is already exported from Relude"
rhs: prettySrcLoc
- warn:
lhs: GHC.Stack.withFrozenCallStack
name: "Use 'withFrozenCallStack' from Relude"
note: "'withFrozenCallStack' is already exported from Relude"
rhs: withFrozenCallStack
- warn:
lhs: Data.Bifoldable.Bifoldable
name: "Use 'Bifoldable' from Relude"
note: "'Bifoldable' is already exported from Relude"
rhs: Bifoldable
- warn:
lhs: Data.Bifoldable.bifold
name: "Use 'bifold' from Relude"
note: "'bifold' is already exported from Relude"
rhs: bifold
- warn:
lhs: Data.Bifoldable.bifoldMap
name: "Use 'bifoldMap' from Relude"
note: "'bifoldMap' is already exported from Relude"
rhs: bifoldMap
- warn:
lhs: Data.Bifoldable.bifoldr
name: "Use 'bifoldr' from Relude"
note: "'bifoldr' is already exported from Relude"
rhs: bifoldr
- warn:
lhs: Data.Bifoldable.bifoldl
name: "Use 'bifoldl' from Relude"
note: "'bifoldl' is already exported from Relude"
rhs: bifoldl
- warn:
lhs: "Data.Bifoldable.bifoldl'"
name: "Use 'bifoldl'' from Relude"
note: "'bifoldl'' is already exported from Relude"
rhs: "bifoldl'"
- warn:
lhs: Data.Bifoldable.bifoldlM
name: "Use 'bifoldlM' from Relude"
note: "'bifoldlM' is already exported from Relude"
rhs: bifoldlM
- warn:
lhs: "Data.Bifoldable.bifoldr'"
name: "Use 'bifoldr'' from Relude"
note: "'bifoldr'' is already exported from Relude"
rhs: "bifoldr'"
- warn:
lhs: Data.Bifoldable.bifoldrM
name: "Use 'bifoldrM' from Relude"
note: "'bifoldrM' is already exported from Relude"
rhs: bifoldrM
- warn:
lhs: Data.Bifoldable.bitraverse_
name: "Use 'bitraverse_' from Relude"
note: "'bitraverse_' is already exported from Relude"
rhs: bitraverse_
- warn:
lhs: Data.Bifoldable.bifor_
name: "Use 'bifor_' from Relude"
note: "'bifor_' is already exported from Relude"
rhs: bifor_
- warn:
lhs: Data.Bifoldable.biasum
name: "Use 'biasum' from Relude"
note: "'biasum' is already exported from Relude"
rhs: biasum
- warn:
lhs: Data.Bifoldable.bisequence_
name: "Use 'bisequence_' from Relude"
note: "'bisequence_' is already exported from Relude"
rhs: bisequence_
- warn:
lhs: Data.Bifoldable.biList
name: "Use 'biList' from Relude"
note: "'biList' is already exported from Relude"
rhs: biList
- warn:
lhs: Data.Bifoldable.binull
name: "Use 'binull' from Relude"
note: "'binull' is already exported from Relude"
rhs: binull
- warn:
lhs: Data.Bifoldable.bilength
name: "Use 'bilength' from Relude"
note: "'bilength' is already exported from Relude"
rhs: bilength
- warn:
lhs: Data.Bifoldable.bielem
name: "Use 'bielem' from Relude"
note: "'bielem' is already exported from Relude"
rhs: bielem
- warn:
lhs: Data.Bifoldable.biand
name: "Use 'biand' from Relude"
note: "'biand' is already exported from Relude"
rhs: biand
- warn:
lhs: Data.Bifoldable.bior
name: "Use 'bior' from Relude"
note: "'bior' is already exported from Relude"
rhs: bior
- warn:
lhs: Data.Bifoldable.biany
name: "Use 'biany' from Relude"
note: "'biany' is already exported from Relude"
rhs: biany
- warn:
lhs: Data.Bifoldable.biall
name: "Use 'biall' from Relude"
note: "'biall' is already exported from Relude"
rhs: biall
- warn:
lhs: Data.Bifoldable.bifind
name: "Use 'bifind' from Relude"
note: "'bifind' is already exported from Relude"
rhs: bifind
- warn:
lhs: Data.Bitraversable.Bitraversable
name: "Use 'Bitraversable' from Relude"
note: "'Bitraversable' is already exported from Relude"
rhs: Bitraversable
- warn:
lhs: Data.Bitraversable.bitraverse
name: "Use 'bitraverse' from Relude"
note: "'bitraverse' is already exported from Relude"
rhs: bitraverse
- warn:
lhs: Data.Bitraversable.bisequence
name: "Use 'bisequence' from Relude"
note: "'bisequence' is already exported from Relude"
rhs: bisequence
- warn:
lhs: Data.Bitraversable.bifor
name: "Use 'bifor' from Relude"
note: "'bifor' is already exported from Relude"
rhs: bifor
- warn:
lhs: Data.Bitraversable.bimapDefault
name: "Use 'bimapDefault' from Relude"
note: "'bimapDefault' is already exported from Relude"
rhs: bimapDefault
- warn:
lhs: Data.Bitraversable.bifoldMapDefault
name: "Use 'bifoldMapDefault' from Relude"
note: "'bifoldMapDefault' is already exported from Relude"
rhs: bifoldMapDefault
- warn:
lhs: Control.Monad.guard
name: "Use 'guard' from Relude"
note: "'guard' is already exported from Relude"
rhs: guard
- warn:
lhs: Control.Monad.unless
name: "Use 'unless' from Relude"
note: "'unless' is already exported from Relude"
rhs: unless
- warn:
lhs: Control.Monad.when
name: "Use 'when' from Relude"
note: "'when' is already exported from Relude"
rhs: when
- warn:
lhs: Data.Bool.bool
name: "Use 'bool' from Relude"
note: "'bool' is already exported from Relude"
rhs: bool
- warn:
lhs: Data.Hashable.Hashable
name: "Use 'Hashable' from Relude"
note: "'Hashable' is already exported from Relude"
rhs: Hashable
- warn:
lhs: Data.Hashable.hashWithSalt
name: "Use 'hashWithSalt' from Relude"
note: "'hashWithSalt' is already exported from Relude"
rhs: hashWithSalt
- warn:
lhs: Data.HashMap.Strict.HashMap
name: "Use 'HashMap' from Relude"
note: "'HashMap' is already exported from Relude"
rhs: HashMap
- warn:
lhs: Data.HashSet.HashSet
name: "Use 'HashSet' from Relude"
note: "'HashSet' is already exported from Relude"
rhs: HashSet
- warn:
lhs: Data.IntMap.Strict.IntMap
name: "Use 'IntMap' from Relude"
note: "'IntMap' is already exported from Relude"
rhs: IntMap
- warn:
lhs: Data.IntSet.IntSet
name: "Use 'IntSet' from Relude"
note: "'IntSet' is already exported from Relude"
rhs: IntSet
- warn:
lhs: Data.Map.Strict.Map
name: "Use 'Map' from Relude"
note: "'Map' is already exported from Relude"
rhs: Map
- warn:
lhs: Data.Sequence.Sequence
name: "Use 'Sequence' from Relude"
note: "'Sequence' is already exported from Relude"
rhs: Sequence
- warn:
lhs: Data.Set.Set
name: "Use 'Set' from Relude"
note: "'Set' is already exported from Relude"
rhs: Set
- warn:
lhs: Data.Tuple.swap
name: "Use 'swap' from Relude"
note: "'swap' is already exported from Relude"
rhs: swap
- warn:
lhs: Data.Vector.Vector
name: "Use 'Vector' from Relude"
note: "'Vector' is already exported from Relude"
rhs: Vector
- warn:
lhs: GHC.Exts.IsList
name: "Use 'IsList' from Relude"
note: "'IsList' is already exported from Relude"
rhs: IsList
- warn:
lhs: GHC.Exts.fromList
name: "Use 'fromList' from Relude"
note: "'fromList' is already exported from Relude"
rhs: fromList
- warn:
lhs: GHC.Exts.fromListN
name: "Use 'fromListN' from Relude"
note: "'fromListN' is already exported from Relude"
rhs: fromListN
- warn:
lhs: Debug.Trace.trace
name: "Use 'trace' from Relude"
note: "'trace' is already exported from Relude"
rhs: trace
- warn:
lhs: Debug.Trace.traceShow
name: "Use 'traceShow' from Relude"
note: "'traceShow' is already exported from Relude"
rhs: traceShow
- warn:
lhs: Debug.Trace.traceShowId
name: "Use 'traceShowId' from Relude"
note: "'traceShowId' is already exported from Relude"
rhs: traceShowId
- warn:
lhs: Debug.Trace.traceShowM
name: "Use 'traceShowM' from Relude"
note: "'traceShowM' is already exported from Relude"
rhs: traceShowM
- warn:
lhs: Debug.Trace.traceM
name: "Use 'traceM' from Relude"
note: "'traceM' is already exported from Relude"
rhs: traceM
- warn:
lhs: Debug.Trace.traceId
name: "Use 'traceId' from Relude"
note: "'traceId' is already exported from Relude"
rhs: traceId
- warn:
lhs: Control.DeepSeq.NFData
name: "Use 'NFData' from Relude"
note: "'NFData' is already exported from Relude"
rhs: NFData
- warn:
lhs: Control.DeepSeq.rnf
name: "Use 'rnf' from Relude"
note: "'rnf' is already exported from Relude"
rhs: rnf
- warn:
lhs: Control.DeepSeq.deepseq
name: "Use 'deepseq' from Relude"
note: "'deepseq' is already exported from Relude"
rhs: deepseq
- warn:
lhs: Control.DeepSeq.force
name: "Use 'force' from Relude"
note: "'force' is already exported from Relude"
rhs: force
- warn:
lhs: "(Control.DeepSeq.$!!)"
name: "Use '$!!' from Relude"
note: "Operator '($!!)' is already exported from Relude"
rhs: "($!!)"
- warn:
lhs: Control.Exception.Exception
name: "Use 'Exception' from Relude"
note: "'Exception' is already exported from Relude"
rhs: Exception
- warn:
lhs: Control.Exception.SomeException
name: "Use 'SomeException' from Relude"
note: "'SomeException' is already exported from Relude"
rhs: SomeException
- warn:
lhs: Control.Exception.toException
name: "Use 'toException' from Relude"
note: "'toException' is already exported from Relude"
rhs: toException
- warn:
lhs: Control.Exception.fromException
name: "Use 'fromException' from Relude"
note: "'fromException' is already exported from Relude"
rhs: fromException
- warn:
lhs: Control.Exception.displayException
name: "Use 'displayException' from Relude"
note: "'displayException' is already exported from Relude"
rhs: displayException
- warn:
lhs: Data.Foldable.asum
name: "Use 'asum' from Relude"
note: "'asum' is already exported from Relude"
rhs: asum
- warn:
lhs: Data.Foldable.find
name: "Use 'find' from Relude"
note: "'find' is already exported from Relude"
rhs: find
- warn:
lhs: Data.Foldable.find
name: "Use 'find' from Relude"
note: "'find' is already exported from Relude"
rhs: find
# - warn:
# lhs: Data.Foldable.fold
# name: "Use 'fold' from Relude"
# note: "'fold' is already exported from Relude"
# rhs: fold
- warn:
lhs: "Data.Foldable.foldl'"
name: "Use 'foldl'' from Relude"
note: "'foldl'' is already exported from Relude"
rhs: "foldl'"
- warn:
lhs: Data.Foldable.forM_
name: "Use 'forM_' from Relude"
note: "'forM_' is already exported from Relude"
rhs: forM_
- warn:
lhs: Data.Foldable.for_
name: "Use 'for_' from Relude"
note: "'for_' is already exported from Relude"
rhs: for_
- warn:
lhs: Data.Foldable.sequenceA_
name: "Use 'sequenceA_' from Relude"
note: "'sequenceA_' is already exported from Relude"
rhs: sequenceA_
- warn:
lhs: Data.Foldable.toList
name: "Use 'toList' from Relude"
note: "'toList' is already exported from Relude"
rhs: toList
- warn:
lhs: Data.Foldable.traverse_
name: "Use 'traverse_' from Relude"
note: "'traverse_' is already exported from Relude"
rhs: traverse_
- warn:
lhs: Data.Traversable.forM
name: "Use 'forM' from Relude"
note: "'forM' is already exported from Relude"
rhs: forM
- warn:
lhs: Data.Traversable.mapAccumL
name: "Use 'mapAccumL' from Relude"
note: "'mapAccumL' is already exported from Relude"
rhs: mapAccumL
- warn:
lhs: Data.Traversable.mapAccumR
name: "Use 'mapAccumR' from Relude"
note: "'mapAccumR' is already exported from Relude"
rhs: mapAccumR
- warn:
lhs: "(Control.Arrow.&&&)"
name: "Use '&&&' from Relude"
note: "Operator '(&&&)' is already exported from Relude"
rhs: "(&&&)"
- warn:
lhs: "(Control.Category.>>>)"
name: "Use '>>>' from Relude"
note: "Operator '(>>>)' is already exported from Relude"
rhs: "(>>>)"
- warn:
lhs: "(Control.Category.<<<)"
name: "Use '<<<' from Relude"
note: "Operator '(<<<)' is already exported from Relude"
rhs: "(<<<)"
- warn:
lhs: Data.Function.fix
name: "Use 'fix' from Relude"
note: "'fix' is already exported from Relude"
rhs: fix
- warn:
lhs: Data.Function.on
name: "Use 'on' from Relude"
note: "'on' is already exported from Relude"
rhs: 'on'
- warn:
lhs: Data.Bifunctor.Bifunctor
name: "Use 'Bifunctor' from Relude"
note: "'Bifunctor' is already exported from Relude"
rhs: Bifunctor
- warn:
lhs: Data.Bifunctor.bimap
name: "Use 'bimap' from Relude"
note: "'bimap' is already exported from Relude"
rhs: bimap
- warn:
lhs: Data.Bifunctor.first
name: "Use 'first' from Relude"
note: "'first' is already exported from Relude"
rhs: first
- warn:
lhs: Data.Bifunctor.second
name: "Use 'second' from Relude"
note: "'second' is already exported from Relude"
rhs: second
- warn:
lhs: Data.Functor.void
name: "Use 'void' from Relude"
note: "'void' is already exported from Relude"
rhs: void
- warn:
lhs: "(Data.Functor.$>)"
name: "Use '$>' from Relude"
note: "Operator '($>)' is already exported from Relude"
rhs: "($>)"
- warn:
lhs: "(Data.Functor.<&>)"
name: "Use '<&>' from Relude"
note: "Operator '(<&>)' is already exported from Relude"
rhs: "(<&>)"
- warn:
lhs: Data.Functor.Compose.Compose
name: "Use 'Compose' from Relude"
note: "'Compose' is already exported from Relude"
rhs: Compose
- warn:
lhs: Data.Functor.Compose.getCompose
name: "Use 'getCompose' from Relude"
note: "'getCompose' is already exported from Relude"
rhs: getCompose
- warn:
lhs: Data.Functor.Identity.Identity
name: "Use 'Identity' from Relude"
note: "'Identity' is already exported from Relude"
rhs: Identity
- warn:
lhs: Data.Functor.Identity.runIdentity
name: "Use 'runIdentity' from Relude"
note: "'runIdentity' is already exported from Relude"
rhs: runIdentity
- warn:
lhs: Control.Concurrent.MVar.MVar
name: "Use 'MVar' from Relude"
note: "'MVar' is already exported from Relude"
rhs: MVar
- warn:
lhs: Control.Concurrent.MVar.newEmptyMVar
name: "Use 'newEmptyMVar' from Relude"
note: "'newEmptyMVar' is already exported from Relude"
rhs: newEmptyMVar
- warn:
lhs: Control.Concurrent.MVar.newMVar
name: "Use 'newMVar' from Relude"
note: "'newMVar' is already exported from Relude"
rhs: newMVar
- warn:
lhs: Control.Concurrent.MVar.putMVar
name: "Use 'putMVar' from Relude"
note: "'putMVar' is already exported from Relude"
rhs: putMVar
- warn:
lhs: Control.Concurrent.MVar.readMVar
name: "Use 'readMVar' from Relude"
note: "'readMVar' is already exported from Relude"
rhs: readMVar
- warn:
lhs: Control.Concurrent.MVar.swapMVar
name: "Use 'swapMVar' from Relude"
note: "'swapMVar' is already exported from Relude"
rhs: swapMVar
- warn:
lhs: Control.Concurrent.MVar.takeMVar
name: "Use 'takeMVar' from Relude"
note: "'takeMVar' is already exported from Relude"
rhs: takeMVar
- warn:
lhs: Control.Concurrent.MVar.tryPutMVar
name: "Use 'tryPutMVar' from Relude"
note: "'tryPutMVar' is already exported from Relude"
rhs: tryPutMVar
- warn:
lhs: Control.Concurrent.MVar.tryReadMVar
name: "Use 'tryReadMVar' from Relude"
note: "'tryReadMVar' is already exported from Relude"
rhs: tryReadMVar
- warn:
lhs: Control.Concurrent.MVar.tryTakeMVar
name: "Use 'tryTakeMVar' from Relude"
note: "'tryTakeMVar' is already exported from Relude"
rhs: tryTakeMVar
- warn:
lhs: Control.Monad.STM.STM
name: "Use 'STM' from Relude"
note: "'STM' is already exported from Relude"
rhs: STM
- warn:
lhs: Control.Monad.STM.atomically
name: "Use 'atomically' from Relude"
note: "'atomically' is already exported from Relude"
rhs: atomically
- warn:
lhs: Control.Monad.STM.throwSTM
name: "Use 'throwSTM' from Relude"
note: "'throwSTM' is already exported from Relude"
rhs: throwSTM
- warn:
lhs: Control.Monad.STM.catchSTM
name: "Use 'catchSTM' from Relude"
note: "'catchSTM' is already exported from Relude"
rhs: catchSTM
- warn:
lhs: Control.Concurrent.STM.TVar.TVar
name: "Use 'TVar' from Relude"
note: "'TVar' is already exported from Relude"
rhs: TVar
- warn:
lhs: Control.Concurrent.STM.TVar.newTVarIO
name: "Use 'newTVarIO' from Relude"
note: "'newTVarIO' is already exported from Relude"
rhs: newTVarIO
- warn:
lhs: Control.Concurrent.STM.TVar.readTVarIO
name: "Use 'readTVarIO' from Relude"
note: "'readTVarIO' is already exported from Relude"
rhs: readTVarIO
- warn:
lhs: "Control.Concurrent.STM.TVar.modifyTVar'"
name: "Use 'modifyTVar'' from Relude"
note: "'modifyTVar'' is already exported from Relude"
rhs: "modifyTVar'"
- warn:
lhs: Control.Concurrent.STM.TVar.newTVar
name: "Use 'newTVar' from Relude"
note: "'newTVar' is already exported from Relude"
rhs: newTVar
- warn:
lhs: Control.Concurrent.STM.TVar.readTVar
name: "Use 'readTVar' from Relude"
note: "'readTVar' is already exported from Relude"
rhs: readTVar
- warn:
lhs: Control.Concurrent.STM.TVar.writeTVar
name: "Use 'writeTVar' from Relude"
note: "'writeTVar' is already exported from Relude"
rhs: writeTVar
- warn:
lhs: Control.Concurrent.STM.TMVar.TMVar
name: "Use 'TMVar' from Relude"
note: "'TMVar' is already exported from Relude"
rhs: TMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.newTMVar
name: "Use 'newTMVar' from Relude"
note: "'newTMVar' is already exported from Relude"
rhs: newTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.newEmptyTMVar
name: "Use 'newEmptyTMVar' from Relude"
note: "'newEmptyTMVar' is already exported from Relude"
rhs: newEmptyTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.newTMVarIO
name: "Use 'newTMVarIO' from Relude"
note: "'newTMVarIO' is already exported from Relude"
rhs: newTMVarIO
- warn:
lhs: Control.Concurrent.STM.TMVar.newEmptyTMVarIO
name: "Use 'newEmptyTMVarIO' from Relude"
note: "'newEmptyTMVarIO' is already exported from Relude"
rhs: newEmptyTMVarIO
- warn:
lhs: Control.Concurrent.STM.TMVar.takeTMVar
name: "Use 'takeTMVar' from Relude"
note: "'takeTMVar' is already exported from Relude"
rhs: takeTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.putTMVar
name: "Use 'putTMVar' from Relude"
note: "'putTMVar' is already exported from Relude"
rhs: putTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.readTMVar
name: "Use 'readTMVar' from Relude"
note: "'readTMVar' is already exported from Relude"
rhs: readTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.tryReadTMVar
name: "Use 'tryReadTMVar' from Relude"
note: "'tryReadTMVar' is already exported from Relude"
rhs: tryReadTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.swapTMVar
name: "Use 'swapTMVar' from Relude"
note: "'swapTMVar' is already exported from Relude"
rhs: swapTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.tryTakeTMVar
name: "Use 'tryTakeTMVar' from Relude"
note: "'tryTakeTMVar' is already exported from Relude"
rhs: tryTakeTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.tryPutTMVar
name: "Use 'tryPutTMVar' from Relude"
note: "'tryPutTMVar' is already exported from Relude"
rhs: tryPutTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.isEmptyTMVar
name: "Use 'isEmptyTMVar' from Relude"
note: "'isEmptyTMVar' is already exported from Relude"
rhs: isEmptyTMVar
- warn:
lhs: Control.Concurrent.STM.TMVar.mkWeakTMVar
name: "Use 'mkWeakTMVar' from Relude"
note: "'mkWeakTMVar' is already exported from Relude"
rhs: mkWeakTMVar
- warn:
lhs: Data.IORef.IORef
name: "Use 'IORef' from Relude"
note: "'IORef' is already exported from Relude"
rhs: IORef
- warn:
lhs: Data.IORef.atomicModifyIORef
name: "Use 'atomicModifyIORef' from Relude"
note: "'atomicModifyIORef' is already exported from Relude"
rhs: atomicModifyIORef
- warn:
lhs: "Data.IORef.atomicModifyIORef'"
name: "Use 'atomicModifyIORef'' from Relude"
note: "'atomicModifyIORef'' is already exported from Relude"
rhs: "atomicModifyIORef'"
- warn:
lhs: Data.IORef.atomicWriteIORef
name: "Use 'atomicWriteIORef' from Relude"
note: "'atomicWriteIORef' is already exported from Relude"
rhs: atomicWriteIORef
- warn:
lhs: Data.IORef.modifyIORef
name: "Use 'modifyIORef' from Relude"
note: "'modifyIORef' is already exported from Relude"
rhs: modifyIORef
- warn:
lhs: "Data.IORef.modifyIORef'"
name: "Use 'modifyIORef'' from Relude"
note: "'modifyIORef'' is already exported from Relude"
rhs: "modifyIORef'"
- warn:
lhs: Data.IORef.newIORef
name: "Use 'newIORef' from Relude"
note: "'newIORef' is already exported from Relude"
rhs: newIORef
- warn:
lhs: Data.IORef.readIORef
name: "Use 'readIORef' from Relude"
note: "'readIORef' is already exported from Relude"
rhs: readIORef
- warn:
lhs: Data.IORef.writeIORef
name: "Use 'writeIORef' from Relude"
note: "'writeIORef' is already exported from Relude"
rhs: writeIORef
- warn:
lhs: "atomicModifyIORef ref (\\a -> (f a, ()))"
rhs: atomicModifyIORef_ ref f
- warn:
lhs: "atomicModifyIORef ref $ \\a -> (f a, ())"
rhs: atomicModifyIORef_ ref f
- warn:
lhs: "atomicModifyIORef' ref $ \\a -> (f a, ())"
rhs: "atomicModifyIORef'_ ref f"
- warn:
lhs: "atomicModifyIORef' ref (\\a -> (f a, ()))"
rhs: "atomicModifyIORef'_ ref f"
- warn:
lhs: Data.Text.IO.getLine
name: "Use 'getLine' from Relude"
note: "'getLine' is already exported from Relude"
rhs: getLine
- warn:
lhs: System.IO.hFlush
name: "Use 'hFlush' from Relude"
note: "'hFlush' is already exported from Relude"
rhs: hFlush
- warn:
lhs: System.IO.hIsEOF
name: "Use 'hIsEOF' from Relude"
note: "'hIsEOF' is already exported from Relude"
rhs: hIsEOF
- warn:
lhs: System.IO.hSetBuffering
name: "Use 'hSetBuffering' from Relude"
note: "'hSetBuffering' is already exported from Relude"
rhs: hSetBuffering
- warn:
lhs: System.IO.hGetBuffering
name: "Use 'hGetBuffering' from Relude"
note: "'hGetBuffering' is already exported from Relude"
rhs: hGetBuffering
- warn:
lhs: System.IO.Handle
name: "Use 'Handle' from Relude"
note: "'Handle' is already exported from Relude"
rhs: Handle
- warn:
lhs: System.IO.stdin
name: "Use 'stdin' from Relude"
note: "'stdin' is already exported from Relude"
rhs: stdin
- warn:
lhs: System.IO.stdout
name: "Use 'stdout' from Relude"
note: "'stdout' is already exported from Relude"
rhs: stdout
- warn:
lhs: System.IO.stderr
name: "Use 'stderr' from Relude"
note: "'stderr' is already exported from Relude"
rhs: stderr
- warn:
lhs: System.IO.withFile
name: "Use 'withFile' from Relude"
note: "'withFile' is already exported from Relude"
rhs: withFile
- warn:
lhs: System.IO.BufferMode
name: "Use 'BufferMode' from Relude"
note: "'BufferMode' is already exported from Relude"
rhs: BufferMode
- warn:
lhs: System.Environment.getArgs
name: "Use 'getArgs' from Relude"
note: "'getArgs' is already exported from Relude"
rhs: getArgs
- warn:
lhs: System.Environment.lookupEnv
name: "Use 'lookupEnv' from Relude"
note: "'lookupEnv' is already exported from Relude"
rhs: lookupEnv
- warn:
lhs: Data.List.genericDrop
name: "Use 'genericDrop' from Relude"
note: "'genericDrop' is already exported from Relude"
rhs: genericDrop
- warn:
lhs: Data.List.genericLength
name: "Use 'genericLength' from Relude"
note: "'genericLength' is already exported from Relude"
rhs: genericLength
- warn:
lhs: Data.List.genericReplicate
name: "Use 'genericReplicate' from Relude"
note: "'genericReplicate' is already exported from Relude"
rhs: genericReplicate
- warn:
lhs: Data.List.genericSplitAt
name: "Use 'genericSplitAt' from Relude"
note: "'genericSplitAt' is already exported from Relude"
rhs: genericSplitAt
- warn:
lhs: Data.List.genericTake
name: "Use 'genericTake' from Relude"
note: "'genericTake' is already exported from Relude"
rhs: genericTake
- warn:
lhs: Data.List.group
name: "Use 'group' from Relude"
note: "'group' is already exported from Relude"
rhs: group
- warn:
lhs: Data.List.inits
name: "Use 'inits' from Relude"
note: "'inits' is already exported from Relude"
rhs: inits
- warn:
lhs: Data.List.intercalate
name: "Use 'intercalate' from Relude"
note: "'intercalate' is already exported from Relude"
rhs: intercalate
- warn:
lhs: Data.List.intersperse
name: "Use 'intersperse' from Relude"
note: "'intersperse' is already exported from Relude"
rhs: intersperse
- warn:
lhs: Data.List.isPrefixOf
name: "Use 'isPrefixOf' from Relude"
note: "'isPrefixOf' is already exported from Relude"
rhs: isPrefixOf
- warn:
lhs: Data.List.permutations
name: "Use 'permutations' from Relude"
note: "'permutations' is already exported from Relude"
rhs: permutations
- warn:
lhs: "Data.List.scanl'"
name: "Use 'scanl'' from Relude"
note: "'scanl'' is already exported from Relude"
rhs: "scanl'"
- warn:
lhs: Data.List.sort
name: "Use 'sort' from Relude"
note: "'sort' is already exported from Relude"
rhs: sort
- warn:
lhs: Data.List.sortBy
name: "Use 'sortBy' from Relude"
note: "'sortBy' is already exported from Relude"
rhs: sortBy
- warn:
lhs: Data.List.sortOn
name: "Use 'sortOn' from Relude"
note: "'sortOn' is already exported from Relude"
rhs: sortOn
- warn:
lhs: Data.List.subsequences
name: "Use 'subsequences' from Relude"
note: "'subsequences' is already exported from Relude"
rhs: subsequences
- warn:
lhs: Data.List.tails
name: "Use 'tails' from Relude"
note: "'tails' is already exported from Relude"
rhs: tails
- warn:
lhs: Data.List.transpose
name: "Use 'transpose' from Relude"
note: "'transpose' is already exported from Relude"
rhs: transpose
- warn:
lhs: Data.List.uncons
name: "Use 'uncons' from Relude"
note: "'uncons' is already exported from Relude"
rhs: uncons
- warn:
lhs: Data.List.unfoldr
name: "Use 'unfoldr' from Relude"
note: "'unfoldr' is already exported from Relude"
rhs: unfoldr
- warn:
lhs: Data.List.NonEmpty.NonEmpty
name: "Use 'NonEmpty' from Relude"
note: "'NonEmpty' is already exported from Relude"
rhs: NonEmpty
- warn:
lhs: "(Data.List.NonEmpty.:|)"
name: "Use ':|' from Relude"
note: "Operator '(:|)' is already exported from Relude"
rhs: "(:|)"
- warn:
lhs: Data.List.NonEmpty.nonEmpty
name: "Use 'nonEmpty' from Relude"
note: "'nonEmpty' is already exported from Relude"
rhs: nonEmpty
- warn:
lhs: Data.List.NonEmpty.head
name: "Use 'head' from Relude"
note: "'head' is already exported from Relude"
rhs: head
- warn:
lhs: Data.List.NonEmpty.init
name: "Use 'init' from Relude"
note: "'init' is already exported from Relude"
rhs: init
- warn:
lhs: Data.List.NonEmpty.last
name: "Use 'last' from Relude"
note: "'last' is already exported from Relude"
rhs: last
- warn:
lhs: Data.List.NonEmpty.tail
name: "Use 'tail' from Relude"
note: "'tail' is already exported from Relude"
rhs: tail
- warn:
lhs: GHC.Exts.sortWith
name: "Use 'sortWith' from Relude"
note: "'sortWith' is already exported from Relude"
rhs: sortWith
- warn:
lhs: Control.Monad.Except.ExceptT
name: "Use 'ExceptT' from Relude"
note: "'ExceptT' is already exported from Relude"
rhs: ExceptT
- warn:
lhs: Control.Monad.Except.runExceptT
name: "Use 'runExceptT' from Relude"
note: "'runExceptT' is already exported from Relude"
rhs: runExceptT
- warn:
lhs: Control.Monad.Reader.MonadReader
name: "Use 'MonadReader' from Relude"
note: "'MonadReader' is already exported from Relude"
rhs: MonadReader
- warn:
lhs: Control.Monad.Reader.Reader
name: "Use 'Reader' from Relude"
note: "'Reader' is already exported from Relude"
rhs: Reader
- warn:
lhs: Control.Monad.Reader.ReaderT
name: "Use 'ReaderT' from Relude"
note: "'ReaderT' is already exported from Relude"
rhs: ReaderT
- warn:
lhs: Control.Monad.Reader.runReaderT
name: "Use 'runReaderT' from Relude"
note: "'runReaderT' is already exported from Relude"
rhs: runReaderT
- warn:
lhs: Control.Monad.Reader.ask
name: "Use 'ask' from Relude"
note: "'ask' is already exported from Relude"
rhs: ask
- warn:
lhs: Control.Monad.Reader.asks
name: "Use 'asks' from Relude"
note: "'asks' is already exported from Relude"
rhs: asks
- warn:
lhs: Control.Monad.Reader.local
name: "Use 'local' from Relude"
note: "'local' is already exported from Relude"
rhs: local
- warn:
lhs: Control.Monad.Reader.reader
name: "Use 'reader' from Relude"
note: "'reader' is already exported from Relude"
rhs: reader
- warn:
lhs: Control.Monad.Reader.runReader
name: "Use 'runReader' from Relude"
note: "'runReader' is already exported from Relude"
rhs: runReader
- warn:
lhs: Control.Monad.Reader.withReader
name: "Use 'withReader' from Relude"
note: "'withReader' is already exported from Relude"
rhs: withReader
- warn:
lhs: Control.Monad.Reader.withReaderT
name: "Use 'withReaderT' from Relude"
note: "'withReaderT' is already exported from Relude"
rhs: withReaderT
- warn:
lhs: Control.Monad.State.Strict.MonadState
name: "Use 'MonadState' from Relude"
note: "'MonadState' is already exported from Relude"
rhs: MonadState
- warn:
lhs: Control.Monad.State.Strict.State
name: "Use 'State' from Relude"
note: "'State' is already exported from Relude"
rhs: State
- warn:
lhs: Control.Monad.State.Strict.StateT
name: "Use 'StateT' from Relude"
note: "'StateT' is already exported from Relude"
rhs: StateT
- warn:
lhs: Control.Monad.State.Strict.runStateT
name: "Use 'runStateT' from Relude"
note: "'runStateT' is already exported from Relude"
rhs: runStateT
- warn:
lhs: Control.Monad.State.Strict.evalState
name: "Use 'evalState' from Relude"
note: "'evalState' is already exported from Relude"
rhs: evalState
- warn:
lhs: Control.Monad.State.Strict.evalStateT
name: "Use 'evalStateT' from Relude"
note: "'evalStateT' is already exported from Relude"
rhs: evalStateT
- warn:
lhs: Control.Monad.State.Strict.execState
name: "Use 'execState' from Relude"
note: "'execState' is already exported from Relude"
rhs: execState
- warn:
lhs: Control.Monad.State.Strict.execStateT
name: "Use 'execStateT' from Relude"
note: "'execStateT' is already exported from Relude"
rhs: execStateT
- warn:
lhs: Control.Monad.State.Strict.get
name: "Use 'get' from Relude"
note: "'get' is already exported from Relude"
rhs: get
- warn:
lhs: Control.Monad.State.Strict.gets
name: "Use 'gets' from Relude"
note: "'gets' is already exported from Relude"
rhs: gets
- warn:
lhs: Control.Monad.State.Strict.modify
name: "Use 'modify' from Relude"
note: "'modify' is already exported from Relude"
rhs: modify
- warn:
lhs: "Control.Monad.State.Strict.modify'"
name: "Use 'modify'' from Relude"
note: "'modify'' is already exported from Relude"
rhs: "modify'"
- warn:
lhs: Control.Monad.State.Strict.put
name: "Use 'put' from Relude"
note: "'put' is already exported from Relude"
rhs: put
- warn:
lhs: Control.Monad.State.Strict.runState
name: "Use 'runState' from Relude"
note: "'runState' is already exported from Relude"
rhs: runState
- warn:
lhs: Control.Monad.State.Strict.state
name: "Use 'state' from Relude"
note: "'state' is already exported from Relude"
rhs: state
- warn:
lhs: Control.Monad.State.Strict.withState
name: "Use 'withState' from Relude"
note: "'withState' is already exported from Relude"
rhs: withState
- warn:
lhs: Control.Monad.Trans.MonadIO
name: "Use 'MonadIO' from Relude"
note: "'MonadIO' is already exported from Relude"
rhs: MonadIO
- warn:
lhs: Control.Monad.Trans.MonadTrans
name: "Use 'MonadTrans' from Relude"
note: "'MonadTrans' is already exported from Relude"
rhs: MonadTrans
- warn:
lhs: Control.Monad.Trans.lift
name: "Use 'lift' from Relude"
note: "'lift' is already exported from Relude"
rhs: lift
- warn:
lhs: Control.Monad.Trans.liftIO
name: "Use 'liftIO' from Relude"
note: "'liftIO' is already exported from Relude"
rhs: liftIO
- warn:
lhs: Control.Monad.Trans.Identity.IdentityT
name: "Use 'IdentityT' from Relude"
note: "'IdentityT' is already exported from Relude"
rhs: IdentityT
- warn:
lhs: Control.Monad.Trans.Identity.runIdentityT
name: "Use 'runIdentityT' from Relude"
note: "'runIdentityT' is already exported from Relude"
rhs: runIdentityT
- warn:
lhs: Control.Monad.Trans.Maybe.MaybeT
name: "Use 'MaybeT' from Relude"
note: "'MaybeT' is already exported from Relude"
rhs: MaybeT
- warn:
lhs: Control.Monad.Trans.Maybe.maybeToExceptT
name: "Use 'maybeToExceptT' from Relude"
note: "'maybeToExceptT' is already exported from Relude"
rhs: maybeToExceptT
- warn:
lhs: Control.Monad.Trans.Maybe.exceptToMaybeT
name: "Use 'exceptToMaybeT' from Relude"
note: "'exceptToMaybeT' is already exported from Relude"
rhs: exceptToMaybeT
- warn:
lhs: Control.Monad.MonadPlus
name: "Use 'MonadPlus' from Relude"
note: "'MonadPlus' is already exported from Relude"
rhs: MonadPlus
- warn:
lhs: Control.Monad.mzero
name: "Use 'mzero' from Relude"
note: "'mzero' is already exported from Relude"
rhs: mzero
- warn:
lhs: Control.Monad.mplus
name: "Use 'mplus' from Relude"
note: "'mplus' is already exported from Relude"
rhs: mplus
- warn:
lhs: Control.Monad.filterM
name: "Use 'filterM' from Relude"
note: "'filterM' is already exported from Relude"
rhs: filterM
- warn:
lhs: Control.Monad.forever
name: "Use 'forever' from Relude"
note: "'forever' is already exported from Relude"
rhs: forever
- warn:
lhs: Control.Monad.join
name: "Use 'join' from Relude"
note: "'join' is already exported from Relude"
rhs: join
- warn:
lhs: Control.Monad.mapAndUnzipM
name: "Use 'mapAndUnzipM' from Relude"
note: "'mapAndUnzipM' is already exported from Relude"
rhs: mapAndUnzipM
- warn:
lhs: Control.Monad.mfilter
name: "Use 'mfilter' from Relude"
note: "'mfilter' is already exported from Relude"
rhs: mfilter
- warn:
lhs: Control.Monad.replicateM
name: "Use 'replicateM' from Relude"
note: "'replicateM' is already exported from Relude"
rhs: replicateM
- warn:
lhs: Control.Monad.replicateM_
name: "Use 'replicateM_' from Relude"
note: "'replicateM_' is already exported from Relude"
rhs: replicateM_
- warn:
lhs: Control.Monad.zipWithM
name: "Use 'zipWithM' from Relude"
note: "'zipWithM' is already exported from Relude"
rhs: zipWithM
- warn:
lhs: Control.Monad.zipWithM_
name: "Use 'zipWithM_' from Relude"
note: "'zipWithM_' is already exported from Relude"
rhs: zipWithM_
- warn:
lhs: "(Control.Monad.<$!>)"
name: "Use '<$!>' from Relude"
note: "Operator '(<$!>)' is already exported from Relude"
rhs: "(<$!>)"
- warn:
lhs: "(Control.Monad.<=<)"
name: "Use '<=<' from Relude"
note: "Operator '(<=<)' is already exported from Relude"
rhs: "(<=<)"
- warn:
lhs: "(Control.Monad.=<<)"
name: "Use '=<<' from Relude"
note: "Operator '(=<<)' is already exported from Relude"
rhs: "(=<<)"
- warn:
lhs: "(Control.Monad.>=>)"
name: "Use '>=>' from Relude"
note: "Operator '(>=>)' is already exported from Relude"
rhs: "(>=>)"
- warn:
lhs: Control.Monad.Fail.MonadFail
name: "Use 'MonadFail' from Relude"
note: "'MonadFail' is already exported from Relude"
rhs: MonadFail
- warn:
lhs: Data.Maybe.catMaybes
name: "Use 'catMaybes' from Relude"
note: "'catMaybes' is already exported from Relude"
rhs: catMaybes
- warn:
lhs: Data.Maybe.fromMaybe
name: "Use 'fromMaybe' from Relude"
note: "'fromMaybe' is already exported from Relude"
rhs: fromMaybe
- warn:
lhs: Data.Maybe.isJust
name: "Use 'isJust' from Relude"
note: "'isJust' is already exported from Relude"
rhs: isJust
- warn:
lhs: Data.Maybe.isNothing
name: "Use 'isNothing' from Relude"
note: "'isNothing' is already exported from Relude"
rhs: isNothing
- warn:
lhs: Data.Maybe.listToMaybe
name: "Use 'listToMaybe' from Relude"
note: "'listToMaybe' is already exported from Relude"
rhs: listToMaybe
- warn:
lhs: Data.Maybe.mapMaybe
name: "Use 'mapMaybe' from Relude"
note: "'mapMaybe' is already exported from Relude"
rhs: mapMaybe
- warn:
lhs: Data.Maybe.maybeToList
name: "Use 'maybeToList' from Relude"
note: "'maybeToList' is already exported from Relude"
rhs: maybeToList
- warn:
lhs: Data.Either.isLeft
name: "Use 'isLeft' from Relude"
note: "'isLeft' is already exported from Relude"
rhs: isLeft
- warn:
lhs: Data.Either.isRight
name: "Use 'isRight' from Relude"
note: "'isRight' is already exported from Relude"
rhs: isRight
- warn:
lhs: Data.Either.lefts
name: "Use 'lefts' from Relude"
note: "'lefts' is already exported from Relude"
rhs: lefts
- warn:
lhs: Data.Either.partitionEithers
name: "Use 'partitionEithers' from Relude"
note: "'partitionEithers' is already exported from Relude"
rhs: partitionEithers
- warn:
lhs: Data.Either.rights
name: "Use 'rights' from Relude"
note: "'rights' is already exported from Relude"
rhs: rights
- warn:
lhs: Data.Monoid.All
name: "Use 'All' from Relude"
note: "'All' is already exported from Relude"
rhs: All
- warn:
lhs: Data.Monoid.getAll
name: "Use 'getAll' from Relude"
note: "'getAll' is already exported from Relude"
rhs: getAll
- warn:
lhs: Data.Monoid.Alt
name: "Use 'Alt' from Relude"
note: "'Alt' is already exported from Relude"
rhs: Alt
- warn:
lhs: Data.Monoid.getAlt
name: "Use 'getAlt' from Relude"
note: "'getAlt' is already exported from Relude"
rhs: getAlt
- warn:
lhs: Data.Monoid.Any
name: "Use 'Any' from Relude"
note: "'Any' is already exported from Relude"
rhs: Any
- warn:
lhs: Data.Monoid.getAny
name: "Use 'getAny' from Relude"
note: "'getAny' is already exported from Relude"
rhs: getAny
- warn:
lhs: Data.Monoid.Ap
name: "Use 'Ap' from Relude"
note: "'Ap' is already exported from Relude"
rhs: Ap
- warn:
lhs: Data.Monoid.getAp
name: "Use 'getAp' from Relude"
note: "'getAp' is already exported from Relude"
rhs: getAp
- warn:
lhs: Data.Monoid.Dual
name: "Use 'Dual' from Relude"
note: "'Dual' is already exported from Relude"
rhs: Dual
- warn:
lhs: Data.Monoid.getDual
name: "Use 'getDual' from Relude"
note: "'getDual' is already exported from Relude"
rhs: getDual
- warn:
lhs: Data.Monoid.Endo
name: "Use 'Endo' from Relude"
note: "'Endo' is already exported from Relude"
rhs: Endo
- warn:
lhs: Data.Monoid.appEndo
name: "Use 'appEndo' from Relude"
note: "'appEndo' is already exported from Relude"
rhs: appEndo
- warn:
lhs: Data.Monoid.First
name: "Use 'First' from Relude"
note: "'First' is already exported from Relude"
rhs: First
- warn:
lhs: Data.Monoid.getFirst
name: "Use 'getFirst' from Relude"
note: "'getFirst' is already exported from Relude"
rhs: getFirst
- warn:
lhs: Data.Monoid.Last
name: "Use 'Last' from Relude"
note: "'Last' is already exported from Relude"
rhs: Last
- warn:
lhs: Data.Monoid.getLast
name: "Use 'getLast' from Relude"
note: "'getLast' is already exported from Relude"
rhs: getLast
- warn:
lhs: Data.Monoid.Product
name: "Use 'Product' from Relude"
note: "'Product' is already exported from Relude"
rhs: Product
- warn:
lhs: Data.Monoid.getProduct
name: "Use 'getProduct' from Relude"
note: "'getProduct' is already exported from Relude"
rhs: getProduct
- warn:
lhs: Data.Monoid.Sum
name: "Use 'Sum' from Relude"
note: "'Sum' is already exported from Relude"
rhs: Sum
- warn:
lhs: Data.Monoid.getSum
name: "Use 'getSum' from Relude"
note: "'getSum' is already exported from Relude"
rhs: getSum
- warn:
lhs: Data.Semigroup.Semigroup
name: "Use 'Semigroup' from Relude"
note: "'Semigroup' is already exported from Relude"
rhs: Semigroup
- warn:
lhs: Data.Semigroup.sconcat
name: "Use 'sconcat' from Relude"
note: "'sconcat' is already exported from Relude"
rhs: sconcat
- warn:
lhs: Data.Semigroup.stimes
name: "Use 'stimes' from Relude"
note: "'stimes' is already exported from Relude"
rhs: stimes
- warn:
lhs: "(Data.Semigroup.<>)"
name: "Use '<>' from Relude"
note: "Operator '(<>)' is already exported from Relude"
rhs: "(<>)"
- warn:
lhs: Data.Semigroup.WrappedMonoid
name: "Use 'WrappedMonoid' from Relude"
note: "'WrappedMonoid' is already exported from Relude"
rhs: WrappedMonoid
- warn:
lhs: Data.Semigroup.cycle1
name: "Use 'cycle1' from Relude"
note: "'cycle1' is already exported from Relude"
rhs: cycle1
- warn:
lhs: Data.Semigroup.mtimesDefault
name: "Use 'mtimesDefault' from Relude"
note: "'mtimesDefault' is already exported from Relude"
rhs: mtimesDefault
- warn:
lhs: Data.Semigroup.stimesIdempotent
name: "Use 'stimesIdempotent' from Relude"
note: "'stimesIdempotent' is already exported from Relude"
rhs: stimesIdempotent
- warn:
lhs: Data.Semigroup.stimesIdempotentMonoid
name: "Use 'stimesIdempotentMonoid' from Relude"
note: "'stimesIdempotentMonoid' is already exported from Relude"
rhs: stimesIdempotentMonoid
- warn:
lhs: Data.Semigroup.stimesMonoid
name: "Use 'stimesMonoid' from Relude"
note: "'stimesMonoid' is already exported from Relude"
rhs: stimesMonoid
- warn:
lhs: Data.ByteString.ByteString
name: "Use 'ByteString' from Relude"
note: "'ByteString' is already exported from Relude"
rhs: ByteString
- warn:
lhs: Data.ByteString.Short.ShortByteString
name: "Use 'ShortByteString' from Relude"
note: "'ShortByteString' is already exported from Relude"
rhs: ShortByteString
- warn:
lhs: Data.ByteString.Short.toShort
name: "Use 'toShort' from Relude"
note: "'toShort' is already exported from Relude"
rhs: toShort
- warn:
lhs: Data.ByteString.Short.fromShort
name: "Use 'fromShort' from Relude"
note: "'fromShort' is already exported from Relude"
rhs: fromShort
- warn:
lhs: Data.String.IsString
name: "Use 'IsString' from Relude"
note: "'IsString' is already exported from Relude"
rhs: IsString
- warn:
lhs: Data.String.fromString
name: "Use 'fromString' from Relude"
note: "'fromString' is already exported from Relude"
rhs: fromString
- warn:
lhs: Data.Text.Text
name: "Use 'Text' from Relude"
note: "'Text' is already exported from Relude"
rhs: Text
- warn:
lhs: Data.Text.lines
name: "Use 'lines' from Relude"
note: "'lines' is already exported from Relude"
rhs: lines
- warn:
lhs: Data.Text.unlines
name: "Use 'unlines' from Relude"
note: "'unlines' is already exported from Relude"
rhs: unlines
- warn:
lhs: Data.Text.words
name: "Use 'words' from Relude"
note: "'words' is already exported from Relude"
rhs: words
- warn:
lhs: Data.Text.unwords
name: "Use 'unwords' from Relude"
note: "'unwords' is already exported from Relude"
rhs: unwords
- warn:
lhs: "Data.Text.Encoding.decodeUtf8'"
name: "Use 'decodeUtf8'' from Relude"
note: "'decodeUtf8'' is already exported from Relude"
rhs: "decodeUtf8'"
- warn:
lhs: Data.Text.Encoding.decodeUtf8With
name: "Use 'decodeUtf8With' from Relude"
note: "'decodeUtf8With' is already exported from Relude"
rhs: decodeUtf8With
- warn:
lhs: Data.Text.Encoding.Error.OnDecodeError
name: "Use 'OnDecodeError' from Relude"
note: "'OnDecodeError' is already exported from Relude"
rhs: OnDecodeError
- warn:
lhs: Data.Text.Encoding.Error.OnError
name: "Use 'OnError' from Relude"
note: "'OnError' is already exported from Relude"
rhs: OnError
- warn:
lhs: Data.Text.Encoding.Error.UnicodeException
name: "Use 'UnicodeException' from Relude"
note: "'UnicodeException' is already exported from Relude"
rhs: UnicodeException
- warn:
lhs: Data.Text.Encoding.Error.lenientDecode
name: "Use 'lenientDecode' from Relude"
note: "'lenientDecode' is already exported from Relude"
rhs: lenientDecode
- warn:
lhs: Data.Text.Encoding.Error.strictDecode
name: "Use 'strictDecode' from Relude"
note: "'strictDecode' is already exported from Relude"
rhs: strictDecode
- warn:
lhs: Text.Read.Read
name: "Use 'Read' from Relude"
note: "'Read' is already exported from Relude"
rhs: Read
- warn:
lhs: Text.Read.readMaybe
name: "Use 'readMaybe' from Relude"
note: "'readMaybe' is already exported from Relude"
rhs: readMaybe
- warn:
lhs: "(liftIO (newEmptyMVar ))"
name: "'liftIO' is not needed"
note: "If you import 'newEmptyMVar' from Relude, it's already lifted"
rhs: newEmptyMVar
- warn:
lhs: "(liftIO (newMVar x))"
name: "'liftIO' is not needed"
note: "If you import 'newMVar' from Relude, it's already lifted"
rhs: newMVar
- warn:
lhs: "(liftIO (putMVar x y))"
name: "'liftIO' is not needed"
note: "If you import 'putMVar' from Relude, it's already lifted"
rhs: putMVar
- warn:
lhs: "(liftIO (readMVar x))"
name: "'liftIO' is not needed"
note: "If you import 'readMVar' from Relude, it's already lifted"
rhs: readMVar
- warn:
lhs: "(liftIO (swapMVar x y))"
name: "'liftIO' is not needed"
note: "If you import 'swapMVar' from Relude, it's already lifted"
rhs: swapMVar
- warn:
lhs: "(liftIO (takeMVar x))"
name: "'liftIO' is not needed"
note: "If you import 'takeMVar' from Relude, it's already lifted"
rhs: takeMVar
- warn:
lhs: "(liftIO (tryPutMVar x y))"
name: "'liftIO' is not needed"
note: "If you import 'tryPutMVar' from Relude, it's already lifted"
rhs: tryPutMVar
- warn:
lhs: "(liftIO (tryReadMVar x))"
name: "'liftIO' is not needed"
note: "If you import 'tryReadMVar' from Relude, it's already lifted"
rhs: tryReadMVar
- warn:
lhs: "(liftIO (tryTakeMVar x))"
name: "'liftIO' is not needed"
note: "If you import 'tryTakeMVar' from Relude, it's already lifted"
rhs: tryTakeMVar
- warn:
lhs: "(liftIO (atomically x))"
name: "'liftIO' is not needed"
note: "If you import 'atomically' from Relude, it's already lifted"
rhs: atomically
- warn:
lhs: "(liftIO (newTVarIO x))"
name: "'liftIO' is not needed"
note: "If you import 'newTVarIO' from Relude, it's already lifted"
rhs: newTVarIO
- warn:
lhs: "(liftIO (readTVarIO x))"
name: "'liftIO' is not needed"
note: "If you import 'readTVarIO' from Relude, it's already lifted"
rhs: readTVarIO
- warn:
lhs: "(liftIO (newTMVarIO x))"
name: "'liftIO' is not needed"
note: "If you import 'newTMVarIO' from Relude, it's already lifted"
rhs: newTMVarIO
- warn:
lhs: "(liftIO (newEmptyTMVarIO ))"
name: "'liftIO' is not needed"
note: "If you import 'newEmptyTMVarIO' from Relude, it's already lifted"
rhs: newEmptyTMVarIO
- warn:
lhs: "(liftIO (exitWith x))"
name: "'liftIO' is not needed"
note: "If you import 'exitWith' from Relude, it's already lifted"
rhs: exitWith
- warn:
lhs: "(liftIO (exitFailure ))"
name: "'liftIO' is not needed"
note: "If you import 'exitFailure' from Relude, it's already lifted"
rhs: exitFailure
- warn:
lhs: "(liftIO (exitSuccess ))"
name: "'liftIO' is not needed"
note: "If you import 'exitSuccess' from Relude, it's already lifted"
rhs: exitSuccess
- warn:
lhs: "(liftIO (die x))"
name: "'liftIO' is not needed"
note: "If you import 'die' from Relude, it's already lifted"
rhs: die
- warn:
lhs: "(liftIO (readFile x))"
name: "'liftIO' is not needed"
note: "If you import 'readFile' from Relude, it's already lifted"
rhs: readFile
- warn:
lhs: "(liftIO (writeFile x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeFile' from Relude, it's already lifted"
rhs: writeFile
- warn:
lhs: "(liftIO (appendFile x y))"
name: "'liftIO' is not needed"
note: "If you import 'appendFile' from Relude, it's already lifted"
rhs: appendFile
- warn:
lhs: "(liftIO (readFileText x))"
name: "'liftIO' is not needed"
note: "If you import 'readFileText' from Relude, it's already lifted"
rhs: readFileText
- warn:
lhs: "(liftIO (writeFileText x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeFileText' from Relude, it's already lifted"
rhs: writeFileText
- warn:
lhs: "(liftIO (appendFileText x y))"
name: "'liftIO' is not needed"
note: "If you import 'appendFileText' from Relude, it's already lifted"
rhs: appendFileText
- warn:
lhs: "(liftIO (readFileLText x))"
name: "'liftIO' is not needed"
note: "If you import 'readFileLText' from Relude, it's already lifted"
rhs: readFileLText
- warn:
lhs: "(liftIO (writeFileLText x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeFileLText' from Relude, it's already lifted"
rhs: writeFileLText
- warn:
lhs: "(liftIO (appendFileLText x y))"
name: "'liftIO' is not needed"
note: "If you import 'appendFileLText' from Relude, it's already lifted"
rhs: appendFileLText
- warn:
lhs: "(liftIO (readFileBS x))"
name: "'liftIO' is not needed"
note: "If you import 'readFileBS' from Relude, it's already lifted"
rhs: readFileBS
- warn:
lhs: "(liftIO (writeFileBS x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeFileBS' from Relude, it's already lifted"
rhs: writeFileBS
- warn:
lhs: "(liftIO (appendFileBS x y))"
name: "'liftIO' is not needed"
note: "If you import 'appendFileBS' from Relude, it's already lifted"
rhs: appendFileBS
- warn:
lhs: "(liftIO (readFileLBS x))"
name: "'liftIO' is not needed"
note: "If you import 'readFileLBS' from Relude, it's already lifted"
rhs: readFileLBS
- warn:
lhs: "(liftIO (writeFileLBS x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeFileLBS' from Relude, it's already lifted"
rhs: writeFileLBS
- warn:
lhs: "(liftIO (appendFileLBS x y))"
name: "'liftIO' is not needed"
note: "If you import 'appendFileLBS' from Relude, it's already lifted"
rhs: appendFileLBS
- warn:
lhs: "(liftIO (newIORef x))"
name: "'liftIO' is not needed"
note: "If you import 'newIORef' from Relude, it's already lifted"
rhs: newIORef
- warn:
lhs: "(liftIO (readIORef x))"
name: "'liftIO' is not needed"
note: "If you import 'readIORef' from Relude, it's already lifted"
rhs: readIORef
- warn:
lhs: "(liftIO (writeIORef x y))"
name: "'liftIO' is not needed"
note: "If you import 'writeIORef' from Relude, it's already lifted"
rhs: writeIORef
- warn:
lhs: "(liftIO (modifyIORef x y))"
name: "'liftIO' is not needed"
note: "If you import 'modifyIORef' from Relude, it's already lifted"
rhs: modifyIORef
- warn:
lhs: "(liftIO (modifyIORef' x y))"
name: "'liftIO' is not needed"
note: "If you import 'modifyIORef'' from Relude, it's already lifted"
rhs: "modifyIORef'"
- warn:
lhs: "(liftIO (atomicModifyIORef x y))"
name: "'liftIO' is not needed"
note: "If you import 'atomicModifyIORef' from Relude, it's already lifted"
rhs: atomicModifyIORef
- warn:
lhs: "(liftIO (atomicModifyIORef' x y))"
name: "'liftIO' is not needed"
note: "If you import 'atomicModifyIORef'' from Relude, it's already lifted"
rhs: "atomicModifyIORef'"
- warn:
lhs: "(liftIO (atomicWriteIORef x y))"
name: "'liftIO' is not needed"
note: "If you import 'atomicWriteIORef' from Relude, it's already lifted"
rhs: atomicWriteIORef
- warn:
lhs: "(liftIO (getLine ))"
name: "'liftIO' is not needed"
note: "If you import 'getLine' from Relude, it's already lifted"
rhs: getLine
- warn:
lhs: "(liftIO (print x))"
name: "'liftIO' is not needed"
note: "If you import 'print' from Relude, it's already lifted"
rhs: print
- warn:
lhs: "(liftIO (putStr x))"
name: "'liftIO' is not needed"
note: "If you import 'putStr' from Relude, it's already lifted"
rhs: putStr
- warn:
lhs: "(liftIO (putStrLn x))"
name: "'liftIO' is not needed"
note: "If you import 'putStrLn' from Relude, it's already lifted"
rhs: putStrLn
- warn:
lhs: "(liftIO (putText x))"
name: "'liftIO' is not needed"
note: "If you import 'putText' from Relude, it's already lifted"
rhs: putText
- warn:
lhs: "(liftIO (putTextLn x))"
name: "'liftIO' is not needed"
note: "If you import 'putTextLn' from Relude, it's already lifted"
rhs: putTextLn
- warn:
lhs: "(liftIO (putLText x))"
name: "'liftIO' is not needed"
note: "If you import 'putLText' from Relude, it's already lifted"
rhs: putLText
- warn:
lhs: "(liftIO (putLTextLn x))"
name: "'liftIO' is not needed"
note: "If you import 'putLTextLn' from Relude, it's already lifted"
rhs: putLTextLn
- warn:
lhs: "(liftIO (putBS x))"
name: "'liftIO' is not needed"
note: "If you import 'putBS' from Relude, it's already lifted"
rhs: putBS
- warn:
lhs: "(liftIO (putBSLn x))"
name: "'liftIO' is not needed"
note: "If you import 'putBSLn' from Relude, it's already lifted"
rhs: putBSLn
- warn:
lhs: "(liftIO (putLBS x))"
name: "'liftIO' is not needed"
note: "If you import 'putLBS' from Relude, it's already lifted"
rhs: putLBS
- warn:
lhs: "(liftIO (putLBSLn x))"
name: "'liftIO' is not needed"
note: "If you import 'putLBSLn' from Relude, it's already lifted"
rhs: putLBSLn
- warn:
lhs: "(liftIO (hFlush x))"
name: "'liftIO' is not needed"
note: "If you import 'hFlush' from Relude, it's already lifted"
rhs: hFlush
- warn:
lhs: "(liftIO (hIsEOF x))"
name: "'liftIO' is not needed"
note: "If you import 'hIsEOF' from Relude, it's already lifted"
rhs: hIsEOF
- warn:
lhs: "(liftIO (hSetBuffering x y))"
name: "'liftIO' is not needed"
note: "If you import 'hSetBuffering' from Relude, it's already lifted"
rhs: hSetBuffering
- warn:
lhs: "(liftIO (hGetBuffering x))"
name: "'liftIO' is not needed"
note: "If you import 'hGetBuffering' from Relude, it's already lifted"
rhs: hGetBuffering
- warn:
lhs: "(liftIO (getArgs ))"
name: "'liftIO' is not needed"
note: "If you import 'getArgs' from Relude, it's already lifted"
rhs: getArgs
- warn:
lhs: "(liftIO (lookupEnv x))"
name: "'liftIO' is not needed"
note: "If you import 'lookupEnv' from Relude, it's already lifted"
rhs: lookupEnv
- hint:
lhs: "fmap (bimap f g)"
note: "Use `bimapF` from `Relude.Extra.Bifunctor`"
rhs: bimapF f g
- hint:
lhs: "bimap f g <$> x"
note: "Use `bimapF` from `Relude.Extra.Bifunctor`"
rhs: bimapF f g x
- hint:
lhs: "fmap (first f)"
note: "Use `firstF` from `Relude.Extra.Bifunctor`"
rhs: firstF f
- hint:
lhs: fmap . first
note: "Use `firstF` from `Relude.Extra.Bifunctor`"
rhs: firstF
- hint:
lhs: "fmap (second f)"
note: "Use `secondF` from `Relude.Extra.Bifunctor`"
rhs: secondF f
- hint:
lhs: fmap . second
note: "Use `secondF` from `Relude.Extra.Bifunctor`"
rhs: secondF
- hint:
lhs: "[minBound .. maxBound]"
note: "Use `universe` from `Relude.Extra.Enum`"
rhs: universe
- hint:
lhs: succ
note: "`succ` from `Prelude` is a pure function but it may throw exception. Consider using `next` from `Relude.Extra.Enum` instead."
rhs: next
- hint:
lhs: pred
note: "`pred` from `Prelude` is a pure function but it may throw exception. Consider using `prev` from `Relude.Extra.Enum` instead."
rhs: prev
- hint:
lhs: toEnum
note: "`toEnum` from `Prelude` is a pure function but it may throw exception. Consider using `safeToEnum` from `Relude.Extra.Enum` instead."
rhs: safeToEnum
- hint:
lhs: sum xs / length xs
note: "Use `average` from `Relude.Extra.Foldable`"
rhs: average xs
- hint:
lhs: "\\a -> (a, a)"
note: "Use `dup` from `Relude.Extra.Tuple`"
rhs: dup
- hint:
lhs: "\\a -> (f a, a)"
note: "Use `toFst` from `Relude.Extra.Tuple`"
rhs: toFst f
- hint:
lhs: "\\a -> (a, f a)"
note: "Use `toSnd` from `Relude.Extra.Tuple`"
rhs: toSnd f
- hint:
lhs: fmap . toFst
note: "Use `fmapToFst` from `Relude.Extra.Tuple`"
rhs: fmapToFst
- hint:
lhs: "fmap (toFst f)"
note: "Use `fmapToFst` from `Relude.Extra.Tuple`"
rhs: fmapToFst f
- hint:
lhs: fmap . toSnd
note: "Use `fmapToSnd` from `Relude.Extra.Tuple`"
rhs: fmapToSnd
- hint:
lhs: "fmap (toSnd f)"
note: "Use `fmapToSnd` from `Relude.Extra.Tuple`"
rhs: fmapToSnd f
- hint:
lhs: map . toFst
note: "Use `fmapToFst` from `Relude.Extra.Tuple`"
rhs: fmapToFst
- hint:
lhs: "map (toFst f)"
note: "Use `fmapToFst` from `Relude.Extra.Tuple`"
rhs: fmapToFst f
- hint:
lhs: map . toSnd
note: "Use `fmapToSnd` from `Relude.Extra.Tuple`"
rhs: fmapToSnd
- hint:
lhs: "map (toSnd f)"
note: "Use `fmapToSnd` from `Relude.Extra.Tuple`"
rhs: fmapToSnd f
- hint:
lhs: "fmap (,a) (f a)"
note: "Use `traverseToFst` from `Relude.Extra.Tuple`"
rhs: traverseToFst f a
- hint:
lhs: "fmap (flip (,) a) (f a)"
note: "Use `traverseToFst` from `Relude.Extra.Tuple`"
rhs: traverseToFst f a
- hint:
lhs: "(,a) <$> f a"
note: "Use `traverseToFst` from `Relude.Extra.Tuple`"
rhs: traverseToFst f a
- hint:
lhs: "flip (,) a <$> f a"
note: "Use `traverseToFst` from `Relude.Extra.Tuple`"
rhs: traverseToFst f a
- hint:
lhs: "fmap (a,) (f a)"
note: "Use `traverseToSnd` from `Relude.Extra.Tuple`"
rhs: traverseToSnd f a
- hint:
lhs: "fmap ((,) a) (f a)"
note: "Use `traverseToSnd` from `Relude.Extra.Tuple`"
rhs: traverseToSnd f a
- hint:
lhs: "(a,) <$> f a"
note: "Use `traverseToSnd` from `Relude.Extra.Tuple`"
rhs: traverseToSnd f a
- hint:
lhs: "(,) a <$> f a"
note: "Use `traverseToSnd` from `Relude.Extra.Tuple`"
rhs: traverseToSnd f a
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project (as seen by library users) will be documented in this file.
The CHANGELOG is available on [Github](https://github.com/luc-tielen/souffle-haskell.git/CHANGELOG.md).
## [0.2.0] - Unreleased
### Added
- Logical negation (of a single rule clause)
- Typed hole support
- Comparison operators
- Arithmetic operators (`+`, `-`, `*`, `/`)
- Possibility to link in external functions
- LSP support
- Document highlight
- Hover
- Diagnostics
- Improved dead code elimination
- Optimization passes:
- HoistConstraints (faster searches by narrowing search-space as early as possible)
- CLI: Allow emitting initial and transformed RA IR
- Support named fields in type definitions and extern definitions
- Support transpiling to Souffle
- Support running semantic analysis on multiple threads
### Changed
- Relations now can have additional qualifiers marking them as inputs or
outputs. Not providing any qualifier means it is now an internal fact.
### Fixed
- 0 is now parsed correctly as a number.
- Type holes now correctly show all possible results in a rule.
- BTree implementation is now better suited for large sets of facts
## [0.1.0] - 2022-11-20
### Added
- WebAssembly support
- Support for the `string` data type
- Wildcards are now supported in rule bodies
- Assignments are now supported in rule bodies
- Support for multiple occurences of the same variable in a single clause of
a rule body
- (UTF-8) strings in relations are now supported
- Optimizations on the AST level:
- Copy propagation
- Dead code elimination
### Changed
- Improved error reporting
- Parsing now continues after failure and reports multiple errors back to the
user at once.
### Fixed
- Rules with multiple equalities.
- Edgecase in index selection algorithm. The algorithm now does not take
`NoElem` variants into account.
## [0.0.1] - 2022-06-14
### Added
- First MVP of the compiler! The happy path should work as expected, unsupported
features or semantic errors should result in a (poorly formatted) error.
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
Contact: luc.tielen@gmail.com
## Why have a Code of Conduct?
As contributors and maintainers of this project, we are committed to providing a
friendly, safe and welcoming environment for all, regardless of age, disability,
gender, nationality, race, religion, sexuality, or similar personal
characteristic.
The goal of the Code of Conduct is to specify a baseline standard of behavior so
that people with different social values and communication styles can talk about
Eclair effectively, productively, and respectfully, even in face of
disagreements. The Code of Conduct also provides a mechanism for resolving
conflicts in the community when they arise.
## Our Values
These are the values Eclair developers should aspire to:
- Be friendly and welcoming
- Be kind
- Remember that people have varying communication styles and that not
everyone is using their native language. (Meaning and tone can be lost in
translation.)
- Interpret the arguments of others in good faith, do not seek to disagree.
- When we do disagree, try to understand why.
- Be thoughtful
- Productive communication requires effort. Think about how your words will
be interpreted.
- Remember that sometimes it is best to refrain entirely from commenting.
- Be respectful
- In particular, respect differences of opinion. It is important that we
resolve disagreements and differing views constructively.
- Be constructive
- Avoid derailing: stay on topic; if you want to talk about something else,
start a new conversation.
- Avoid unconstructive criticism: don't merely decry the current state of
affairs; offer — or at least solicit — suggestions as to how things may be
improved.
- Avoid harsh words and stern tone: we are all aligned towards the
well-being of the community and the progress of the ecosystem. Harsh words
exclude, demotivate, and lead to unnecessary conflict.
- Avoid snarking (pithy, unproductive, sniping comments).
- Avoid microaggressions (brief and commonplace verbal, behavioral and
environmental indignities that communicate hostile, derogatory or negative
slights and insults towards a project, person or group).
- Be responsible
- What you say and do matters. Take responsibility for your words and
actions, including their consequences, whether intended or otherwise.
The following actions are explicitly forbidden:
- Insulting, demeaning, hateful, or threatening remarks.
- Discrimination based on age, disability, gender, nationality, race,
religion, sexuality, or similar personal characteristic.
- Bullying or systematic harassment.
- Unwelcome sexual advances.
- Incitement to any of these.
## Where does the Code of Conduct apply?
If you participate in or contribute to the Eclair ecosystem in any way, you are
encouraged to follow the Code of Conduct while doing so.
Explicit enforcement of the Code of Conduct applies to the official mediums
operated by the Eclair project:
- The [official GitHub project][1] and code reviews.
- The **[#Eclair][2]** Discord[2].
Other Eclair activities (such as conferences, meetups, and unofficial forums)
are encouraged to adopt this Code of Conduct. Such groups must provide their own
contact information.
Project maintainers may block, remove, edit, or reject comments, commits, code,
wiki edits, issues, and other contributions that are not aligned to this Code of
Conduct.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by emailing: luc.tielen@gmail.com. All complaints will
be reviewed and investigated and will result in a response that is deemed
necessary and appropriate to the circumstances. **All reports will be kept
confidential**.
**The goal of the Code of Conduct is to resolve conflicts in the most harmonious
way possible**. We hope that in most cases issues may be resolved through polite
discussion and mutual agreement. Bannings and other forceful measures are to be
employed only as a last resort. **Do not** post about the issue publicly or try
to rally sentiment against a particular individual or group.
## Acknowledgements
This document was based on the Code of Conduct from the Elixir project (dated
Jul/2023), which in turn was based on the Go project (dated Sep/2021) and the
Contributor Covenant (v1.4).
[1]: https://github.com/luc-tielen/eclair-lang
[2]: https://discord.gg/mC2arUrxKg
================================================
FILE: Dockerfile
================================================
FROM primordus/souffle-ubuntu:2.3
ARG LLVM_VERSION=17
SHELL [ "/bin/bash", "-c" ]
# install packages
RUN echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections \
&& echo 'tzdata tzdata/Zones/Europe select Paris' | debconf-set-selections \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
wget software-properties-common gnupg curl libffi-dev make \
python3 python3-pip libgmp-dev \
&& curl -o - https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash \
&& source /root/.nvm/nvm.sh \
&& nvm install 18.1.0 \
&& echo "source /root/.ghcup/env" >> ~/.bashrc \
# install llvm 17
&& mkdir -p /tmp/llvm-dir \
&& cd /tmp/llvm-dir \
&& wget https://apt.llvm.org/llvm.sh \
&& chmod +x llvm.sh \
&& ./llvm.sh $LLVM_VERSION \
&& cd /tmp \
&& rm -rf /tmp/llvm-dir \
&& cd /usr/bin \
&& ln -s /usr/lib/llvm-$LLVM_VERSION/bin/split-file \
&& ln -s /usr/lib/llvm-$LLVM_VERSION/bin/FileCheck \
&& ln -s clang-$LLVM_VERSION clang \
&& ln -s wasm-ld-$LLVM_VERSION wasm-ld \
&& cd - \
&& pip install lit==14.0.6 \
# install ghcup, ghc-9.6.3 and cabal-3.10.1.0
&& curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | \
BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_GHC_VERSION=9.6.3 BOOTSTRAP_HASKELL_CABAL_VERSION=3.10.1.0 \
BOOTSTRAP_HASKELL_INSTALL_STACK=1 BOOTSTRAP_HASKELL_INSTALL_HLS=1 BOOTSTRAP_HASKELL_ADJUST_BASHRC=P sh \
&& source /root/.ghcup/env \
&& cabal install cabal-fmt \
&& cabal install hspec-discover \
&& apt-get autoremove -y \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
VOLUME /code
WORKDIR /app/build
ENV DATALOG_DIR=/app/build/cbits
RUN echo -e '#!/bin/bash\nsource /root/.ghcup/env\nsource /root/.nvm/nvm.sh\nexec "$@"\n' > /app/build/entrypoint.sh \
&& chmod u+x /app/build/entrypoint.sh
# The entrypoint script sources ghcup setup script so we can easily call cabal etc.
ENTRYPOINT [ "/app/build/entrypoint.sh" ]
COPY . .
RUN source /root/.ghcup/env && make build \
&& echo -e '#!/bin/bash\nsource /root/.ghcup/env\n' > /usr/bin/eclair \
&& source /root/.ghcup/env \
&& echo -e "`cabal list-bin eclair` \"\$@\"" >> /usr/bin/eclair \
&& chmod u+x /usr/bin/eclair
# The default command to run, shows the help menu
CMD [ "eclair", "--help" ]
================================================
FILE: LICENSE
================================================
Copyright Luc Tielen (c) 2022
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Luc Tielen nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Makefile
================================================
build: configure
@cabal build
configure:
@cabal configure -f eclair-debug --enable-tests
clean:
@cabal clean
test:
@DATALOG_DIR=cbits/ cabal run eclair-test
@lit tests/ -v
cabal-file:
@cabal-fmt --Werror -i eclair-lang.cabal
.PHONY: build configure clean test cabal-file
================================================
FILE: README.md
================================================
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./logo_dark.png"/>
<img
src="./logo_light.png"
alt="Logo for the Eclair programming language"
loading="lazy"
decoding="async"/>
</picture>
_An experimental and minimal Datalog implementation that compiles down to LLVM._
[](https://github.com/luc-tielen/eclair-lang/actions/workflows/build.yml)
## Features
Eclair is a minimal Datalog (for now). It supports the following features:
- Facts containing literals
- Rules consisting of one or more clauses.
- Rules can be non-recursive, recursive or mutually recursive.
Right now it compiles to LLVM but be aware there might still be bugs.
Some edge cases might not be handled yet.
## Motivating example
Let's say we want to find out which points are reachable in a graph. We can
determine which points are reachable using the following two logical rules:
1. One point is reachable from another point, iff there is a direct edge between
those two points.
2. One point is reachable from another point, iff there is a third point 'z' such
that there is a direct edge between 'x' and 'z', and between 'z' and 'y'.
The Eclair code below can be used to calculate the solution:
```eclair
@def edge(u32, u32).
@def reachable(u32, u32).
reachable(x, y) :-
edge(x, y).
reachable(x, z) :-
edge(x, y),
reachable(y, z).
```
The above code can be compiled to LLVM using the Docker image provided by this repo:
```bash
$ git clone git@github.com:luc-tielen/eclair-lang.git
$ cd eclair-lang
$ docker build . -t eclair
# The next line assumes the eclair code is saved as "example.dl" in the current directory
$ docker run -v $PWD:/code --rm -it eclair:latest compile /code/example.dl
# NOTE: output can be redirected to a file using standard shell functionality: docker run ... > example.ll
```
This will emit the generated LLVM IR to the stdout of the terminal. If we save
this generated LLVM IR to a file (e.g. `example.ll`), we can link it with the
following C code that calls into Eclair, using the following command:
`clang -o program main.c example.ll`.
```c
// Save this file as "main.c".
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
struct program;
extern struct program* eclair_program_init();
extern void eclair_program_destroy(struct program*);
extern void eclair_program_run(struct program*);
extern void eclair_add_facts(struct program*, uint16_t fact_type, uint32_t* data, size_t fact_count);
extern void eclair_add_fact(struct program*, uint16_t fact_type, uint32_t* data);
extern uint32_t* eclair_get_facts(struct program*, uint16_t fact_type);
extern void eclair_free_buffer(uint32_t* data);
int main(int argc, char** argv)
{
struct program* prog = eclair_program_init();
// edge(1,2), edge(2,3)
uint32_t data[] = {
1, 2,
2, 3
};
eclair_add_facts(prog, 0, data, 2);
eclair_program_run(prog);
// NOTE: normally you call btree_size here to figure out the size, but I know there are only 3 facts
uint32_t* data_out = eclair_get_facts(prog, 1);
printf("REACHABLE: (%d, %d)\n", data_out[0], data_out[1]); // (1,2)
printf("REACHABLE: (%d, %d)\n", data_out[2], data_out[3]); // (2,3)
printf("REACHABLE: (%d, %d)\n", data_out[4], data_out[5]); // (1,3)
eclair_free_buffer(data_out);
eclair_program_destroy(prog);
return 0;
}
```
If you run the resulting program, this should print the reachable node pairs
`(1,2)`, `(2,3)` and `(1,3)` to the screen!
## Roadmap
- [x] LSP support
- [x] Allow setting options on relations for performance finetuning
- [x] Comparison operators, != operator
- [x] Support arithmetic operators
- [x] Generic, extensible primops
- [x] Support logical negation
- [ ] Release 0.2.0
- [ ] Signed integer type (i32)
- [ ] Unary negation
- [ ] Optimizations on the AST / RA / LLVM level
- [ ] Support other underlying data structures than btree
- [ ] Syntactic sugar (disjunctions in rule bodies, multiple rule heads, ...)
- [ ] Support Datalog programs spanning multiple files
- [ ] ...
This roadmap is not set in stone, but it gives an idea on the direction of the
project. :smile:
## Contributing to Eclair
Contributions are welcome! Take a look at the
[getting started guide](./docs/getting_started.md) on how to set up your machine
to build, run and test the project. Once setup, the Makefile contains the most
commonly used commands needed during development.
You can also use the `Dockerfile` in this repository if you want to experiment
with Eclair without installing the toolchain yourself. You can do that as
follows:
```bash
$ docker build -f Dockerfile . -t eclair
$ touch test.eclair # Here you can put your Eclair code
$ docker run -v $PWD:/code --rm -it eclair eclair compile /code/test.eclair
```
## Documentation
Take a look at our [docs folder](./docs/) for more information about Eclair.
## Why the name?
Eclair is inspired by [Soufflé](https://souffle-lang.github.io/), a high
performance Datalog that compiles to C++. Because of the similarities, I chose a
different kind of food that I like. I mean, an eclair contains _both_ chocolate and
pudding, what's not to like!?
Logo art by [Bruno Monts](https://www.instagram.com/bruno_monts/),
with special thanks to the [Fission](https://fission.codes) team.
Please contact Luc Tielen before using the logo for anything.
================================================
FILE: cabal.project
================================================
packages: .
source-repository-package
type: git
location: https://github.com/luc-tielen/llvm-codegen.git
tag: 83b04cb576208ea74ddd62016e4fa03f0df138ac
source-repository-package
type: git
location: https://github.com/luc-tielen/souffle-haskell.git
tag: e441c84f1d64890e31c92fbb278c074ae8bcaff5
source-repository-package
type: git
location: https://github.com/luc-tielen/diagnose.git
tag: 24a1d7a2b716d74c1fe44d47941a76c9f5a90c23
================================================
FILE: cbits/semantic_analysis.dl
================================================
// Input facts
.decl lit_number(node_id: unsigned, value: unsigned)
.decl lit_string(node_id: unsigned, value: symbol)
.decl variable(node_id: unsigned, var_name: symbol)
.decl constraint(node_id: unsigned, op: symbol, lhs_node_id: unsigned, rhs_node_id: unsigned)
.decl binop(node_id: unsigned, op: symbol, lhs_node_id: unsigned, rhs_node_id: unsigned)
.decl atom(node_id: unsigned, name: symbol)
.decl atom_arg(atom_id: unsigned, atom_arg_pos: unsigned, atom_arg_id: unsigned)
.decl rule(rule_id: unsigned, name: symbol)
.decl rule_arg(rule_id: unsigned, rule_arg_pos: unsigned, rule_arg_id: unsigned)
.decl rule_clause(rule_id: unsigned, rule_clause_pos: unsigned, rule_clause_id: unsigned)
.decl negation(negation_node_id: unsigned, inner_node_id: unsigned)
.decl input_relation(relation_name: symbol)
.decl output_relation(relation_name: symbol)
.decl internal_relation(relation_name: symbol)
.decl extern_definition(node_id: unsigned, extern_name: symbol)
.decl declare_type(node_id: unsigned, name: symbol)
.decl module(node_id: unsigned)
.decl module_declaration(module_id: unsigned, declaration_id: unsigned)
.decl scoped_value(scope_id: unsigned, value_id: unsigned)
// Internal rules
.decl relation_atom(node_id: unsigned, name: symbol)
.decl extern_atom(node_id: unsigned, name: symbol)
.decl grounded_node(rule_node_id: unsigned, node_id: unsigned)
.decl assign(node_id: unsigned, lhs_node_id: unsigned, rhs_node_id: unsigned) inline
.decl inequality_op(op: symbol)
.decl has_output_relation(node_id: unsigned)
.decl literal_contradiction(lit_id1: unsigned, lit_id2: unsigned)
.decl wildcard(node_id: unsigned) inline
.decl rule_head_var(rule_id: unsigned, var_id: unsigned, var_name: symbol)
.decl alias(rule_id: unsigned, id1: unsigned, id2: unsigned)
.decl points_to(rule_id: unsigned, id1: unsigned, id2: unsigned)
.decl depends_on(r1: symbol, r2: symbol)
.decl transitive_depends_on(r1: symbol, r2: symbol)
.decl source(r: symbol)
.decl has_definitions(relation: symbol)
.decl live_rule(relation: symbol)
.decl dependency_cycle(relation: symbol)
.decl rule_scope(rule_id: unsigned, scope_id: unsigned)
.decl constrained_rule_var(rule_node_id: unsigned, var_node_id: unsigned, var_name: symbol)
// Output facts / rules
.decl grounded_variable(rule_id: unsigned, var_name: symbol)
.decl ungrounded_variable(rule_id: unsigned, var_id: unsigned, var_name: symbol)
.decl ungrounded_external_atom(rule_id: unsigned, atom_id: unsigned, atom_name: symbol)
.decl wildcard_in_fact(fact_node_id: unsigned, fact_arg_id: unsigned, pos: unsigned)
.decl wildcard_in_extern(atom_node_id: unsigned, atom_arg_id: unsigned, pos: unsigned)
.decl wildcard_in_rule_head(rule_node_id: unsigned, rule_arg_id: unsigned, pos: unsigned)
.decl wildcard_in_constraint(constraint_node_id: unsigned, wildcard_node_id: unsigned)
.decl wildcard_in_binop(binop_node_id: unsigned, wildcard_node_id: unsigned)
.decl unconstrained_rule_var(rule_node_id: unsigned, var_node_id: unsigned, var_name: symbol)
.decl rule_with_contradiction(rule_id: unsigned)
.decl dead_code(node_id: unsigned)
.decl no_output_relation(node_id: unsigned)
.decl dead_internal_relation(node_id: unsigned, relation_name: symbol)
.decl conflicting_definitions(node_id1: unsigned, node_id2: unsigned, name: symbol)
.decl extern_used_as_fact(node_id: unsigned, extern_node_id: unsigned, name: symbol)
.decl extern_used_as_rule(node_id: unsigned, extern_node_id: unsigned, name: symbol)
.decl cyclic_negation(negation_id: unsigned)
.input lit_number
.input lit_string
.input variable
.input constraint
.input binop
.input atom
.input atom_arg
.input rule
.input rule_arg
.input rule_clause
.input negation
.input input_relation
.input output_relation
.input internal_relation
.input extern_definition
.input declare_type
.input module
.input module_declaration
.input scoped_value
.output wildcard_in_fact
.output wildcard_in_extern
.output ungrounded_variable
.output ungrounded_external_atom
.output wildcard_in_rule_head
.output wildcard_in_constraint
.output wildcard_in_binop
.output unconstrained_rule_var
.output dead_code
.output no_output_relation
.output dead_internal_relation
.output conflicting_definitions
.output extern_used_as_fact
.output extern_used_as_rule
.output cyclic_negation
// An atom that is not defined externally. This is an important distinction
// since external atoms cannot ground variables!
relation_atom(node_id, name) :-
declare_type(_, name),
atom(node_id, name).
// An atom that is defined externally.
extern_atom(node_id, name) :-
extern_definition(_, name),
atom(node_id, name).
// r1 depends on r2 if rule r1 refers to r2 in the body
depends_on(r1, r2) :-
rule(rule_id, r1),
rule_clause(rule_id, _, clause_id),
atom(clause_id, r2).
// Variant for negated atoms.
depends_on(r1, r2) :-
rule(rule_id, r1),
rule_clause(rule_id, _, negation_id),
negation(negation_id, atom_id),
atom(atom_id, r2).
// Variant for extern functions.
depends_on(r1, r2) :-
rule(rule_id, r1),
rule_clause(rule_id, _, assign_id),
assign(assign_id, lhs_node_id, rhs_node_id),
(
extern_atom(lhs_node_id, r2);
extern_atom(rhs_node_id, r2)
).
transitive_depends_on(r1, r2) :-
depends_on(r1, r2).
transitive_depends_on(r1, r3) :-
depends_on(r1, r2),
transitive_depends_on(r2, r3).
// Rules have cyclic dependencies if a rule depends on itself (transitively)
dependency_cycle(r) :-
transitive_depends_on(r, r).
// Negations are not allowed inside a rule if the negated atom is part of a
// dependency cycle since this is not stratifiable.
cyclic_negation(negation_id) :-
dependency_cycle(r1),
transitive_depends_on(r1, r2),
rule(rule_id, r2),
rule_clause(rule_id, _, negation_id),
negation(negation_id, atom_id),
atom(atom_id, r3),
transitive_depends_on(r3, r1).
// An input can always be a source of data.
source(r) :-
input_relation(r).
// An internal or output relation can be a source of data if they define top level facts.
source(r) :-
module_declaration(_, atom_id),
atom(atom_id, r),
!input_relation(r). // internal or output relation
// An output rule is live if it is a direct source of data.
live_rule(r) :-
output_relation(r),
source(r).
// An output rule is live if there is a path from the source to this output.
live_rule(r1) :-
output_relation(r1),
transitive_depends_on(r1, r2),
source(r2).
// A rule is live if it is depended on by another live rule.
live_rule(r2) :-
depends_on(r1, r2),
live_rule(r1).
// Dead rules are the opposite set of all the live rules.
dead_code(node_id) :-
rule(node_id, r),
!live_rule(r).
// Type definitions also need to be marked as dead.
dead_code(node_id) :-
declare_type(node_id, r),
!live_rule(r).
// Extern definitions also need to be marked as dead.
dead_code(node_id) :-
extern_definition(node_id, r),
!live_rule(r).
// Atoms too.
dead_code(node_id) :-
atom(node_id, r),
!live_rule(r).
// Rules are dead if one of the clauses is statically known to produce no results.
dead_code(rule_id) :-
rule_with_contradiction(rule_id).
// A rule is dead if it depends on another dead rule.
// Note that this only looks at one specific rule that contains the dead code, not the entire relation.
dead_code(rule_id) :-
rule_clause(rule_id, _, rule_clause_id),
dead_code(rule_clause_id).
has_definitions(r) :-
module_declaration(_, node_id),
(
atom(node_id, r);
rule(node_id, r)
).
// We consider an internal relation to be dead if there are no top level atoms or rules.
dead_internal_relation(decl_id, r) :-
internal_relation(r),
declare_type(decl_id, r),
!has_definitions(r).
has_output_relation(node_id) :-
module_declaration(node_id, decl_id),
declare_type(decl_id, r),
output_relation(r).
no_output_relation(node_id) :-
module_declaration(node_id, _),
!has_output_relation(node_id).
// Top level facts: no variables allowed
ungrounded_variable(atom_id, var_id, var_name) :-
module_declaration(_, atom_id),
atom(atom_id, _),
scoped_value(atom_id, var_id),
variable(var_id, var_name),
var_name != "_".
// Rules: no variables allowed in rule head if not used in a rule clause
ungrounded_variable(rule_id, var_id, var_name) :-
rule_head_var(rule_id, var_id, var_name),
var_name != "_",
!grounded_variable(rule_id, var_name). // Only compare by variable name!
// Variables used in a constraint (comparison, equality or inequality) need to be grounded.
ungrounded_variable(rule_id, var_id, var_name) :-
rule_clause(rule_id, _, rule_clause_id),
constraint(rule_clause_id, op, var_id, _),
variable(var_id, var_name),
var_name != "_",
!grounded_variable(rule_id, var_name).
ungrounded_variable(rule_id, var_id, var_name) :-
rule_clause(rule_id, _, rule_clause_id),
constraint(rule_clause_id, op, _, var_id),
variable(var_id, var_name),
var_name != "_",
!grounded_variable(rule_id, var_name).
// Variables used in a binop need to be grounded.
ungrounded_variable(rule_id, var_id, var_name) :-
binop(_, _, var_id, _),
variable(var_id, var_name),
scoped_value(scope_id, var_id),
rule_scope(rule_id, scope_id),
!grounded_variable(rule_id, var_name).
ungrounded_variable(rule_id, var_id, var_name) :-
binop(_, _, _, var_id),
variable(var_id, var_name),
scoped_value(scope_id, var_id),
rule_scope(rule_id, scope_id),
!grounded_variable(rule_id, var_name).
// Variables used in a negation need to be grounded.
ungrounded_variable(rule_id, var_id, var_name) :-
negation(negation_id, _),
rule_clause(rule_id, _, negation_id),
scoped_value(negation_id, var_id),
variable(var_id, var_name),
!grounded_node(rule_id, var_id).
// External atoms used in a fact need to be grounded.
ungrounded_external_atom(fact_id, atom_id, atom_name) :-
module_declaration(_, fact_id),
atom_arg(fact_id, _, atom_id),
extern_atom(atom_id, atom_name),
!grounded_node(fact_id, atom_id).
// External atoms used in a rule head need to be grounded.
ungrounded_external_atom(rule_id, atom_id, atom_name) :-
rule_arg(rule_id, _, atom_id),
atom(atom_id, atom_name),
scoped_value(rule_id, atom_id),
!grounded_node(rule_id, atom_id).
// External atoms used in a comparison or inequality need to be grounded.
ungrounded_external_atom(rule_id, atom_id, atom_name) :-
rule_clause(rule_id, _, rule_clause_id),
constraint(rule_clause_id, op, _, atom_id),
inequality_op(op),
atom(atom_id, atom_name),
scoped_value(rule_id, atom_id),
!grounded_node(rule_id, atom_id).
ungrounded_external_atom(rule_id, atom_id, atom_name) :-
rule_clause(rule_id, _, rule_clause_id),
constraint(rule_clause_id, op, atom_id, _),
inequality_op(op),
atom(atom_id, atom_name),
scoped_value(rule_id, atom_id),
!grounded_node(rule_id, atom_id).
// External atoms used in a binop need to be grounded.
ungrounded_external_atom(rule_id, atom_id, atom_name) :-
binop(_, _, _, atom_id),
atom(atom_id, atom_name),
scoped_value(rule_id, atom_id),
!grounded_node(rule_id, atom_id).
ungrounded_external_atom(rule_id, atom_id, atom_name) :-
binop(_, _, atom_id, _),
atom(atom_id, atom_name),
scoped_value(rule_id, atom_id),
!grounded_node(rule_id, atom_id).
rule_scope(rule_id, rule_id) :-
rule(rule_id, _).
rule_scope(rule_id, negation_id) :-
rule_clause(rule_id, _, negation_id),
negation(negation_id, _).
inequality_op("!=").
inequality_op("<").
inequality_op("<=").
inequality_op(">").
inequality_op(">=").
wildcard(node_id) :-
variable(node_id, "_").
wildcard_in_rule_head(rule_id, rule_arg_id, pos) :-
rule_arg(rule_id, pos, rule_arg_id),
wildcard(rule_arg_id).
wildcard_in_fact(atom_id, atom_arg_id, pos) :-
module_declaration(_, atom_id),
atom_arg(atom_id, pos, atom_arg_id),
wildcard(atom_arg_id).
wildcard_in_extern(atom_id, atom_arg_id, pos) :-
rule(rule_id, _),
scoped_value(rule_id, atom_id),
extern_atom(atom_id, _),
atom_arg(atom_id, pos, atom_arg_id),
wildcard(atom_arg_id).
wildcard_in_constraint(constraint_node_id, lhs_node_id) :-
constraint(constraint_node_id, _, lhs_node_id, _),
wildcard(lhs_node_id).
wildcard_in_constraint(constraint_node_id, rhs_node_id) :-
constraint(constraint_node_id, _, _, rhs_node_id),
wildcard(rhs_node_id).
wildcard_in_binop(binop_node_id, lhs_node_id) :-
binop(binop_node_id, _, lhs_node_id, _),
wildcard(lhs_node_id).
wildcard_in_binop(binop_node_id, rhs_node_id) :-
binop(binop_node_id, _, _, rhs_node_id),
wildcard(rhs_node_id).
// A rule variable is unconstrained if there is no other occurrence of the variable in the rule.
// (This works because groundedness of a variable is also checked..
unconstrained_rule_var(rule_id, var_id, var_name) :-
rule_scope(rule_id, scope_id),
scoped_value(scope_id, var_id),
variable(var_id, var_name),
!constrained_rule_var(rule_id, var_id, var_name).
// This could be done much simpler using count aggregate but this is not implemented in Eclair yet.
constrained_rule_var(rule_id, var_id1, var_name) :-
rule_scope(rule_id, scope_id1),
rule_scope(rule_id, scope_id2),
scoped_value(scope_id1, var_id1),
scoped_value(scope_id2, var_id2),
variable(var_id1, var_name),
variable(var_id2, var_name),
var_id1 != var_id2.
assign(node_id, lhs_node_id, rhs_node_id) :-
constraint(node_id, "=", lhs_node_id, rhs_node_id).
// All variables with the same name in a rule are aliases of each other.
alias(rule_id, var_id1, var_id2) :-
scoped_value(rule_id, var_id1),
variable(var_id1, var_name),
scoped_value(rule_id, var_id2),
var_id1 != var_id2,
variable(var_id2, var_name).
// Two values are aliases if they are used inside an equality.
// NOTE: Datalog supports both x = 123 and 123 = x.
alias(rule_id, id1, id2),
alias(rule_id, id2, id1) :-
rule_clause(rule_id, _, rule_clause_id),
assign(rule_clause_id, id1, id2).
// Non-recursive case: what does a variable point to?
points_to(rule_id, id1, id2) :-
alias(rule_id, id1, id2),
variable(id1, _).
// Recursive case: a = b, b = c results in a = c
points_to(rule_id, id1, id4) :-
points_to(rule_id, id1, id2),
variable(id2, var_name),
variable(id3, var_name),
alias(rule_id, id3, id4).
// If we find two variables that point to different literal values,
// then there is a contradiction.
rule_with_contradiction(rule_id) :-
points_to(rule_id, start_id, id1),
points_to(rule_id, start_id, id2),
literal_contradiction(id1, id2).
// This is also true for simple cases like '123 = 456'.
rule_with_contradiction(rule_id) :-
rule_clause(rule_id, _, rule_clause_id),
assign(rule_clause_id, id1, id2),
literal_contradiction(id1, id2).
literal_contradiction(id1, id2) :-
lit_number(id1, value1),
lit_number(id2, value2),
value1 != value2.
literal_contradiction(id1, id2) :-
lit_string(id1, value1),
lit_string(id2, value2),
value1 != value2.
// Helper relation for getting all variables in head of a rule.
rule_head_var(rule_id, var_id, var_name) :-
rule_arg(rule_id, _, var_id),
variable(var_id, var_name).
// Helper relation for getting all grounded variables in body of a rule.
grounded_variable(rule_id, var_name) :-
grounded_node(rule_id, var_id),
variable(var_id, var_name).
// Variables are grounded if they are used in an atom (defined using '@def').
grounded_node(rule_id, var_id) :-
rule_clause(rule_id, _, rule_clause_id),
relation_atom(rule_clause_id, _),
atom_arg(rule_clause_id, _, var_id),
variable(var_id, _).
// All variables with same name are grounded at the same time
grounded_node(rule_id, var_id2) :-
scoped_value(rule_id, var_id1),
variable(var_id1, var_name),
grounded_node(rule_id, var_id1),
scoped_value(rule_id, var_id2),
variable(var_id2, var_name).
// Variables are grounded inside a negation if they are grounded in another clause.
grounded_node(rule_id, var_id2) :-
negation(negation_id, _),
rule_clause(rule_id, _, negation_id),
scoped_value(rule_id, var_id1),
variable(var_id1, var_name),
grounded_node(rule_id, var_id1),
scoped_value(negation_id, var_id2),
variable(var_id2, var_name).
// Literals are always grounded.
grounded_node(rule_id, node_id) :-
scoped_value(rule_id, node_id),
lit_number(node_id, _).
grounded_node(rule_id, node_id) :-
scoped_value(rule_id, node_id),
lit_string(node_id, _).
// A binop is grounded if both sides are grounded.
grounded_node(rule_id, node_id) :-
grounded_node(rule_id, lhs_node_id),
grounded_node(rule_id, rhs_node_id),
binop(node_id, _, lhs_node_id, rhs_node_id).
// Assignment grounds one var, if the other side is already grounded.
grounded_node(rule_id, rhs_node_id) :-
rule_clause(rule_id, _, rule_clause_id),
assign(rule_clause_id, lhs_node_id, rhs_node_id),
grounded_node(rule_id, lhs_node_id),
variable(rhs_node_id, _).
grounded_node(rule_id, lhs_node_id) :-
rule_clause(rule_id, _, rule_clause_id),
assign(rule_clause_id, lhs_node_id, rhs_node_id),
grounded_node(rule_id, rhs_node_id),
variable(lhs_node_id, _).
conflicting_definitions(node_id, node_id2, name) :-
declare_type(node_id, name),
declare_type(node_id2, name),
node_id < node_id2.
conflicting_definitions(node_id, node_id2, name) :-
extern_definition(node_id, name),
extern_definition(node_id2, name),
node_id < node_id2.
conflicting_definitions(node_id, node_id2, name) :-
declare_type(node_id, name),
extern_definition(node_id2, name),
node_id < node_id2.
conflicting_definitions(node_id, node_id2, name) :-
extern_definition(node_id, name),
declare_type(node_id2, name),
node_id < node_id2.
extern_used_as_fact(node_id, extern_node_id, name) :-
extern_definition(extern_node_id, name),
module_declaration(_, node_id),
atom(node_id, name).
extern_used_as_rule(node_id, extern_node_id, name) :-
extern_definition(extern_node_id, name),
rule(node_id, name).
================================================
FILE: docs/architecture_choices.md
================================================
# Architecture choices
This document contains all the high level choices that have been made with
regards to the architecture of the compiler. Besides this document, there are
also [several blogposts](https://luctielen.com/) with deep dives on specific
parts of the compiler.
## Inspired by Souffle
Eclair's approach to compiling high level Datalog syntax to assembly is heavily
inspired by Souffle Datalog (most notably: the compilation to relational algebra
and the minimum index selection algorithm). At the top of the corresponding
source code in Eclair, there is a comment pointing to the paper so contributors
can consult the theoretic background behind the code easily.
Eclair does have some notable differences though. First and foremost: it is
written in Haskell. This choice was made because Haskell makes it easy to
express high level ideas and algorithms that you commonly run into when building
a compiler. As an additional benefit, Haskell already has a great ecosystem of
libraries for building a compiler.
The second big change compared to Souffle is that Eclair compiles down directly
to LLVM instead of C++. This gives greater control of the generated assembly
(assembly is generated using a monad / "builder pattern" instead of
concatenating strings to form a C++ program) and also makes it easily portable
to other platforms (including WebAssembly). On top of that we can leverage
existing LLVM tools to analyze / transform the generated LLVM IR.
## IR Design
Eclair makes use of four different intermediate representations (IRs). Each of
the IRs has a different focus / view of the program. By using multiple IRs, we
can also gradually lower the Datalog syntax to the assembly level.
The four different IRs are:
1. AST
2. RA
3. EIR
4. LLVM IR
Each of these IRs is discussed in the subsections below. Every IR can be pretty
printed for inspection (when debugging a compiler issue or when writing Eclair
code).
Each of the IRs are designed in a similar way: they all consist of a single data
type each. This might be a bit controversial for most Haskellers that value type
safety, but this ends up working out because:
1. The parser, semantic analysis and typesystem steps halt when they determine
the program is invalid;
2. Often we are only interested in a really small part of the IR anyway;
3. Most Haskell libraries support one simple type best.
The singly-typed IR is a conciously made trade-off, but it gives us great
benefits. Transformations (a large part of the compiler!) can be written down
succinctly thanks to the
[recursion-schemes library](https://hackage.haskell.org/package/recursion-schemes).
The transforms are guaranteed to terminate when written this way, and are
automatically composable. Besides that, all algorithms can be written down as a
pattern-match that focuses on only one node of the IR.
Besides having singly-typed IRs, each data constructor in the IR type has a
unique node ID attached to it. This makes it possible to link data from outside
the IR to it, without having to keep modifying the IR over and over. This is
especially useful for the semantic analysis and typesystem parts of the
compiler, since they can refer to parts of the program via a node ID.
### AST
The first IR is the `AST` type. AST stands for "Abstract Syntax Tree" and is a
tree representation of the original source code.
Semantic analysis and typechecking happens on this IR before any transformations
are performed, so we can report back exact locations to users of Eclair.
The AST is the most "high level" / starting IR. AST compiles down to RA, which
is described in the next section.
### RA
`RA` stands for "Relational Algebra". It represents a Eclair Datalog program as
a set of relational algebra operations. The data type is pretty much copied
directly from the Souffle paper, with some minor modifications. By first
transforming the AST to RA, we can subsequently lower the code even further down
to the assembly level (via EIR and LLVM IR).
### EIR
`EIR` is an abbreviation for "Eclair IR". It is a IR designed to be very close
to LLVM IR, but with the focus that it is also easy to debug and inspect. It was
mainly created to make the final lowering to LLVM IR as trivial as possible, but
it ended up being also useful for stitching the various Eclair functions in the
runtime together.
### LLVM IR
The LLVM IR is the final IR this compiler makes use of and bears the closest
resemblance to assembly. The
[llvm-codegen library](https://github.com/luc-tielen/llvm-codegen) is used to
generate LLVM instructions. From this point onwards, we can make use of the LLVM
compiler framework to get many optimizations and other tools all for free.
## Query-based compiler
Eclair is a so-called "query-based compiler". What this means is:
1. Each stage of the compiler builds on top of previous stages,
2. You can query the results of each of these "sub-computations".
This kind of architecture ends up being very useful for a compiler since a
compiler often is not a "pipeline" as it is usually presented, but instead has
a graph structure where later stages can depend on earlier stages. On top of
that, it makes it simple to access information at each stage of the compiler,
making it easy to write tools that can query the compiler as a database. (Useful
for developer tools such as LSP!)
The [rock library](https://hackage.haskell.org/package/rock) builds on top of
this idea and provides an API for describing your compiler in terms of build
system rules.
## The parser
The parser is written using parser combinators (from the `megaparsec` library).
This approach was chosen because now this parser is fully written in Haskell,
making it trivial to integrate with the rest of the compiler. On top of that, it
gives you full control over how the parsing happens. In the Eclair compiler the
parser adds a unique node id to each parsed AST node (see section about IR
design).
## Semantic analysis
Eclair makes use of Souffle Datalog during semantic analysis. Using Datalog for
semantic analysis is great, because you can write all your logic really
succinctly by writing down the "patterns" you are looking for in the AST and let
Datalog deduce all results.
The fact that each AST node has a unique ID (see section about IR design) makes
it easy to refer to certain parts of a program and also to make it easy to
serialize data back and forth between Haskell and Datalog.
Eventually, Eclair will be a bootstrapped compiler, meaning all the parts where
Souffle Datalog is currently used will be swapped out with an Eclair Datalog
counterpart. This will make it much easier to distribute and run the compiler
(since there is one big dependency less required).
## Typesystem
The typesystem is a bidirectional typesystem. This means that the typesystem
either checks a term against an expected type, or it tries to infer a type.
Bidirectional typecheckers are great because they are "straight-forward" to
implement (you pretty much need to write two functions that pattern match on the
syntax and handle each node type correspondingly), and produce better error
messages than typesystems that make heavy use of constraint solving.
On top of this, the typesystem tries to report as many type errors as possible
at once and with additional context how it came to these conclusions. This is
done to make the developer experience better.
## Error rendering
An effort is made to make Eclair errors as clear as possible for developers
(using Rust and Elm for inspiration). Right now we use the
[diagnose library](https://github.com/Mesabloo/diagnose) for reporting the
errors since it allows us to focus on other parts of the compiler, but later
this error rendering system will be implemented in the Eclair codebase itself to
allow for more customization.
## Tranformations
Eclair has a general
[Transform](https://github.com/luc-tielen/eclair-lang/blob/main/lib/Eclair/Transform.hs)
type that can be used for transforming the various IRs. Transformations can have
two goals: they either simplify the IR, or they try to optimize it (or both).
Eclair is a nano-pass compiler. Transformations should be small, focused and
composable; so that you can reason about them. It's better to have a few extra
passes in the compiler instead of a lot of extra complexity. The `Transform`
type provides helper functions and typeclass instances to compose them into
bigger transforms anyway.
Transformations can have local state, but the way it is setup it is impossible
for this state to "leak out" to the outside world. This is again done to make it
easier to reason about, while not limiting what's possible inside a transform.
Finally, transforms always run in a `TransformM` monad. This monad offers a way
of generating new unique node IDs in case extra IR nodes are generated.
## Tests
Currently the Eclair test suite is divided into two parts:
1. Unit tests written directly in Haskell
2. "Integration" tests that are executed by the `lit` executable provided by LLVM.
Over time, most of the tests will be integration tests, since they are more
rigorous and test larger parts of the compiler. On top of that, these style of
tests allow you to write an example directly in Eclair and compare the result
against actual output of the compiler.
================================================
FILE: docs/getting_started.md
================================================
# Getting started
Eclair requires a Haskell toolchain, Souffle 2.3 and LLVM 14 to be installed on
your system.
If you notice that the installation instructions below are incomplete or
outdated, please open a [Github issue](https://github.com/luc-tielen/eclair-lang/issues).
## Pre-requisites
### Ubuntu
NOTE: These commands were tested with Ubuntu 20.04, they may not work with older
versions.
#### Installing the Haskell toolchain
Run the following commands to install `ghcup`, `ghc` and `cabal`. `cabal-fmt`,
`hspec-discover` and `hlint` are also installed but they are only needed when working on the
compiler.
```bash
$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
$ ghcup tui
# In the terminal UI, select GHC 9.2.4, Haskell language server 1.8 and Cabal 3.6.
# Important: both install + set them!
$ cabal install cabal-fmt
$ cabal install hspec-discover
$ cabal install hlint
```
Verify you installed the correct versions by running the commands below, and
comparing them against the versions mentioned in the previous command:
```bash
$ ghc --version
$ haskell-language-server-wrapper --version
$ cabal --version
```
#### Installing Souffle
Run the following commands to download and build Souffle from source:
```bash
$ sudo apt install bison build-essential cmake doxygen flex g++ git \
libffi-dev libncurses5-dev libsqlite3-dev make mcpp python sqlite zlib1g-dev
$ git clone git@github.com:souffle-lang/souffle.git
$ cd souffle
$ git checkout 2.3
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
$ cmake --build build -j
$ sudo cmake --build build --target install
```
If this went correctly, Souffle should now be globally installed on your system.
Check this by executing the following command; it should print out the version
of Souffle (2.3).
```bash
$ souffle --version
```
#### Installing LLVM
Next we need to install LLVM 14. Run the steps below to install it on your
system.
```bash
# If these packages are not available on your system, try installing using this
# link: https://apt.llvm.org/.
$ sudo apt install llvm-14
$ sudo apt install lld-14
$ sudo apt install clang-14 # Optional, if you want to use clang instead of llc
# to compile the LLVM IR
# The following is only needed for development / testing
$ cd ~/.local/bin # Or any other directory that is on your $PATH
$ ln -s /usr/lib/llvm-14/bin/split-file
$ ln -s /usr/bin/FileCheck-14 FileCheck
$ pip install lit==14.0.6
```
### Windows
Assuming you have Windows subsytem for Linux, the commands above should also
work for Windows? (If somebody could verify this, that would be great!)
### OSX
NOTE: These commands were tested with Intel MacOS 13.0, they may or may not not work
with older versions or on an ARM-based machine.
#### Installing the Haskell toolchain
Run the following commands (see https://www.haskell.org/ghcup/) to install `ghcup`, `ghc` and `cabal`.
```bash
$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
$ ghcup tui
# In the terminal UI, select GHC 9.2.4, Haskell language server 1.8 and Cabal 3.6.
# Important: both install + set them!
```
The following commands are only needed when working on the compiler.
Run the commands to install `cabal-fmt`, `hspec-discover`, and `hlint`.
```bash
$ cabal install cabal-fmt
$ cabal install hspec-discover
$ cabal install hlint
```
Verify you installed the correct versions by running the commands below, and
compare them against the versions mentioned in the previous command:
```bash
$ ghc --version
$ haskell-language-server-wrapper --version
$ cabal --version
```
#### Installing Souffle
Run the following commands to download and build Souffle from source
(instructions taken from [here](https://souffle-lang.github.io/build#mac-os-x-build)):
```bash
$ brew update
$ brew install cmake bison libffi mcpp pkg-config
$ brew reinstall gcc
$ brew link bison --force
$ brew link libffi --force
$ brew install souffle-lang/souffle/souffle
```
If this went correctly, Souffle should now be globally installed on your system.
Check this by executing the following command; it should print out the version
of Souffle (2.3).
```bash
$ souffle --version
```
#### Installing LLVM
Next we need to install LLVM 14. Run the steps below to install it on your
system.
```bash
$ brew install llvm@14
# The following is only needed for development / testing
$ cd ~/.local/bin # Or any other directory that is on your $PATH
$ ln -s /usr/local/opt/llvm@14/bin/split-file
$ ln -s /usr/local/opt/llvm@14/bin/FileCheck
$ pip install lit==14.0.6
$ brew install node
```
## Building Eclair
Now that all the pre-requisites are built, you can build Eclair.
```bash
$ cabal build
$ cabal run eclair-test # Unit tests
$ lit tests -v # Integration tests
$ cabal list-bin eclair # <= returns path to the Eclair compiler executable
```
================================================
FILE: eclair-lang.cabal
================================================
cabal-version: 2.2
name: eclair-lang
version: 0.2.0
synopsis:
Eclair: an experimental and minimal Datalog that compiles to LLVM.
description:
Eclair: an experimental and minimal Datalog that compiles to LLVM.
category: Compiler
homepage: https://github.com/luc-tielen/eclair-lang
author: Luc Tielen
maintainer: luc.tielen@gmail.com
copyright: Luc Tielen, 2023
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple
extra-source-files:
cbits/semantic_analysis.dl
CHANGELOG.md
LICENSE
README.md
flag debug
description: Enables stack traces.
manual: True
default: False
library
-- cabal-fmt: expand lib
exposed-modules:
Eclair
Eclair.ArgParser
Eclair.AST.Analysis
Eclair.AST.Codegen
Eclair.AST.IR
Eclair.AST.Lower
Eclair.AST.Transforms
Eclair.AST.Transforms.ConstantFolding
Eclair.AST.Transforms.DeadCodeElimination
Eclair.AST.Transforms.NormalizeRules
Eclair.AST.Transforms.RemoveAliases
Eclair.AST.Transforms.ReplaceStrings
Eclair.Common.Config
Eclair.Common.Extern
Eclair.Common.Id
Eclair.Common.Literal
Eclair.Common.Location
Eclair.Common.Operator
Eclair.Common.Pretty
Eclair.Comonads
Eclair.EIR.IR
Eclair.EIR.Lower
Eclair.EIR.Lower.API
Eclair.EIR.Lower.Codegen
Eclair.EIR.Lower.Externals
Eclair.Error
Eclair.JSON
Eclair.LLVM.Allocator.Arena
Eclair.LLVM.Allocator.Common
Eclair.LLVM.Allocator.Malloc
Eclair.LLVM.Allocator.Page
Eclair.LLVM.BTree
Eclair.LLVM.BTree.Bounds
Eclair.LLVM.BTree.Compare
Eclair.LLVM.BTree.Create
Eclair.LLVM.BTree.Destroy
Eclair.LLVM.BTree.Find
Eclair.LLVM.BTree.Insert
Eclair.LLVM.BTree.Iterator
Eclair.LLVM.BTree.Size
Eclair.LLVM.BTree.Types
Eclair.LLVM.Codegen
Eclair.LLVM.Config
Eclair.LLVM.Externals
Eclair.LLVM.Hash
Eclair.LLVM.HashMap
Eclair.LLVM.Metadata
Eclair.LLVM.Symbol
Eclair.LLVM.SymbolTable
Eclair.LLVM.Table
Eclair.LLVM.Template
Eclair.LLVM.Vector
Eclair.LSP
Eclair.LSP.Handlers
Eclair.LSP.Handlers.Diagnostics
Eclair.LSP.Handlers.DocumentHighlight
Eclair.LSP.Handlers.Hover
Eclair.LSP.JSON
Eclair.LSP.Monad
Eclair.LSP.Types
Eclair.LSP.VFS
Eclair.Parser
Eclair.RA.Codegen
Eclair.RA.IndexSelection
Eclair.RA.IR
Eclair.RA.Lower
Eclair.RA.Transforms
Eclair.RA.Transforms.HoistConstraints
Eclair.Souffle.IR
Eclair.Transform
Eclair.TypeSystem
Prelude
hs-source-dirs: lib
default-extensions:
DataKinds
DeriveAnyClass
DeriveFoldable
DeriveFunctor
DeriveGeneric
DeriveTraversable
DerivingStrategies
DerivingVia
FlexibleContexts
FlexibleInstances
KindSignatures
LambdaCase
OverloadedStrings
PatternSynonyms
RankNTypes
RecursiveDo
ScopedTypeVariables
TupleSections
TypeFamilies
ViewPatterns
ghc-options:
-Wall -Wincomplete-patterns -fhide-source-paths
-fno-show-valid-hole-fits -fno-sort-valid-hole-fits
cxx-options: -std=c++17 -D__EMBEDDED_SOUFFLE__ -Wall
build-depends:
, algebraic-graphs <1
, base >=4.7 && <5
, bytestring >=0.11 && <0.12
, comonad >=5 && <6
, containers <1
, dependent-sum >=0.6 && <1
, diagnose >=2.3 && <2.4
, directory >=1 && <2
, dlist >=1 && <2
, exceptions >=0.10 && <0.11
, extra >=1 && <2
, ghc-prim <1
, hermes-json <1
, llvm-codegen
, megaparsec >=9 && <10
, mmorph >=1 && <2
, mtl >=2 && <3
, optparse-applicative >=0.16 && <0.17
, parser-combinators >=1.3 && <1.4
, prettyprinter >=1.7 && <1.8
, prettyprinter-ansi-terminal >=1 && <2
, recursion-schemes >=5 && <6
, relude >=1.2 && <1.3
, rock >=0.3 && <0.4
, souffle-haskell ==4.0.0
, text >=2 && <3
, text-builder-linear <1
, transformers <1
, vector >=0.12 && <0.13
mixins: base hiding (Prelude)
default-language: Haskell2010
if os(osx)
extra-libraries: c++
if flag(debug)
ghc-options: -fplugin=StackTrace.Plugin
build-depends: haskell-stack-trace-plugin ==0.1.3.0
if os(linux)
extra-libraries: stdc++
executable eclair
main-is: Main.hs
other-modules: Paths_eclair_lang
autogen-modules: Paths_eclair_lang
hs-source-dirs: src/eclair
default-extensions:
DataKinds
DeriveAnyClass
DeriveFoldable
DeriveFunctor
DeriveGeneric
DeriveTraversable
DerivingStrategies
DerivingVia
FlexibleContexts
FlexibleInstances
KindSignatures
LambdaCase
OverloadedStrings
PatternSynonyms
RankNTypes
RecursiveDo
ScopedTypeVariables
TupleSections
TypeFamilies
ViewPatterns
ghc-options:
-Wall -Wincomplete-patterns -fhide-source-paths
-fno-show-valid-hole-fits -fno-sort-valid-hole-fits -threaded
-rtsopts -with-rtsopts=-N
cxx-options: -std=c++17 -D__EMBEDDED_SOUFFLE__
build-depends:
, algebraic-graphs <1
, base >=4.7 && <5
, bytestring >=0.11 && <0.12
, comonad >=5 && <6
, containers <1
, dependent-sum >=0.6 && <1
, diagnose >=2.3 && <2.4
, directory >=1 && <2
, dlist >=1 && <2
, eclair-lang
, exceptions >=0.10 && <0.11
, extra >=1 && <2
, llvm-codegen
, megaparsec >=9 && <10
, mmorph >=1 && <2
, mtl >=2 && <3
, optparse-applicative >=0.16 && <0.17
, parser-combinators >=1.3 && <1.4
, prettyprinter >=1.7 && <1.8
, prettyprinter-ansi-terminal >=1 && <2
, process >=1.6 && <1.7
, recursion-schemes >=5 && <6
, relude >=1.2 && <1.3
, rock >=0.3 && <0.4
, souffle-haskell ==4.0.0
, text >=2 && <3
, transformers <1
, vector >=0.12 && <0.13
mixins: base hiding (Prelude)
default-language: Haskell2010
if os(osx)
extra-libraries: c++
if flag(debug)
ghc-options: -fplugin=StackTrace.Plugin
build-depends: haskell-stack-trace-plugin ==0.1.3.0
test-suite eclair-test
type: exitcode-stdio-1.0
main-is: test.hs
-- cabal-fmt: expand tests/eclair
other-modules:
Paths_eclair_lang
Test.Eclair.ArgParserSpec
Test.Eclair.JSONSpec
Test.Eclair.LLVM.Allocator.MallocSpec
Test.Eclair.LLVM.Allocator.PageSpec
Test.Eclair.LLVM.Allocator.Utils
Test.Eclair.LLVM.BTreeSpec
Test.Eclair.LLVM.HashMapSpec
Test.Eclair.LLVM.HashSpec
Test.Eclair.LLVM.SymbolSpec
Test.Eclair.LLVM.SymbolTableSpec
Test.Eclair.LLVM.SymbolUtils
Test.Eclair.LLVM.VectorSpec
Test.Eclair.LSP.HandlersSpec
Test.Eclair.LSP.JSONSpec
Test.Eclair.RA.IndexSelectionSpec
autogen-modules: Paths_eclair_lang
hs-source-dirs: tests/eclair
default-extensions:
DataKinds
DeriveAnyClass
DeriveFoldable
DeriveFunctor
DeriveGeneric
DeriveTraversable
DerivingStrategies
DerivingVia
FlexibleContexts
FlexibleInstances
KindSignatures
LambdaCase
OverloadedStrings
PatternSynonyms
RankNTypes
RecursiveDo
ScopedTypeVariables
TupleSections
TypeFamilies
ViewPatterns
ghc-options:
-Wall -Wincomplete-patterns -fhide-source-paths
-fno-show-valid-hole-fits -fno-sort-valid-hole-fits
cxx-options: -std=c++17 -D__EMBEDDED_SOUFFLE__
build-depends:
, algebraic-graphs <1
, array >=0.5 && <1
, base >=4.7 && <5
, bytestring >=0.11 && <0.12
, comonad >=5 && <6
, containers <1
, dependent-sum >=0.6 && <1
, diagnose >=2.3 && <2.4
, dlist >=1 && <2
, eclair-lang
, exceptions >=0.10 && <0.11
, extra >=1 && <2
, filepath >=1 && <2
, hedgehog >=1 && <2
, hermes-json <1
, hspec >=2.6.1 && <3.0.0
, hspec-hedgehog <1
, libffi >=0.2 && <1
, llvm-codegen
, megaparsec >=9 && <10
, mmorph >=1 && <2
, mtl >=2 && <3
, neat-interpolation <1
, optparse-applicative >=0.16 && <0.17
, parser-combinators >=1.3 && <1.4
, prettyprinter >=1.7 && <1.8
, prettyprinter-ansi-terminal >=1 && <2
, random >=1.2 && <2
, recursion-schemes >=5 && <6
, relude >=1.2 && <1.3
, rock >=0.3 && <0.4
, silently >=1.2 && <1.3
, souffle-haskell ==4.0.0
, text >=2 && <3
, transformers <1
, unix >=2.8 && <3
, vector >=0.12 && <0.13
mixins: base hiding (Prelude)
default-language: Haskell2010
if os(osx)
extra-libraries: c++
if flag(debug)
ghc-options: -fplugin=StackTrace.Plugin
build-depends: haskell-stack-trace-plugin ==0.1.3.0
================================================
FILE: hie.yaml
================================================
cradle:
cabal:
- path: "lib"
component: "lib:eclair-lang"
- path: "src/eclair/Main.hs"
component: "eclair-lang:exe:eclair"
- path: "src/eclair/Paths_eclair_lang.hs"
component: "eclair-lang:exe:eclair"
- path: "src/lsp"
component: "eclair-lang:exe:eclair-lsp-server"
- path: "tests/eclair"
component: "eclair-lang:test:eclair-test"
- path: "tests/lsp/Main.hs"
component: "eclair-lang:test:eclair-lsp-test"
================================================
FILE: lib/Eclair/AST/Analysis.hs
================================================
{-# LANGUAGE UndecidableInstances #-}
module Eclair.AST.Analysis
( Result(..)
, SemanticInfo(..)
, SemanticErrors(..)
, hasSemanticErrors
, runAnalysis
, UngroundedVar(..)
, WildcardInFact(..)
, WildcardInRuleHead(..)
, WildcardInConstraint(..)
, WildcardInBinOp(..)
, WildcardInExtern(..)
, UnconstrainedRuleVar(..)
, DeadCode(..)
, DeadInternalRelation(..)
, NoOutputRelation(..)
, ConflictingDefinitionGroup(..)
, ExternUsedAsFact(..)
, ExternUsedAsRule(..)
, CyclicNegation(..)
, NodeId(..)
, Container
, computeUsageMapping
) where
import qualified Data.List.NonEmpty as NE
import Data.List.Extra (nubOrdOn)
import qualified Language.Souffle.Interpreted as S
import qualified Language.Souffle.Analysis as S
import qualified Eclair.AST.IR as IR
import qualified Data.Map as Map
import Eclair.Common.Id
import Eclair.Common.Location (NodeId(..))
type Position = Word32
-- The facts submitted to Datalog closely follow the AST structure,
-- but are denormalized so that Datalog can easily process it.
data LitNumber
= LitNumber NodeId Word32
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions LitNumber "lit_number" 'S.Input
data LitString
= LitString NodeId Text
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions LitString "lit_string" 'S.Input
data Var
= Var NodeId Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Var "variable" 'S.Input
newtype Hole
= Hole NodeId
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Hole "hole" 'S.Input
data Constraint
= Constraint
{ constraintId :: NodeId
, constraintOperator :: Text
, constraintLhsId :: NodeId
, constraintRhsId :: NodeId
}
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Constraint "constraint" 'S.Input
data BinOp
= BinOp
{ binOpId :: NodeId
, op :: Text
, binOpLhsId :: NodeId
, binOpRhsId :: NodeId
}
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions BinOp "binop" 'S.Input
data Atom
= Atom NodeId Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Atom "atom" 'S.Input
data AtomArg
= AtomArg { atomId :: NodeId, atomArgPos :: Word32, atomArgId :: NodeId }
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions AtomArg "atom_arg" 'S.Input
data Rule
= Rule NodeId Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Rule "rule" 'S.Input
data RuleArg
= RuleArg { raRuleId :: NodeId, raArgPos :: Word32, raArgId :: NodeId }
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions RuleArg "rule_arg" 'S.Input
data RuleClause
= RuleClause { rcRuleId :: NodeId, rcClausePos :: Word32, rcClauseId :: NodeId }
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions RuleClause "rule_clause" 'S.Input
data Negation
= Negation
{ negationNodeId :: NodeId
, negationInnerNodeId :: NodeId
}
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Negation "negation" 'S.Input
-- NOTE: not storing types right now, but might be useful later?
data DeclareType
= DeclareType NodeId Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions DeclareType "declare_type" 'S.Input
data ExternDefinition
= ExternDefinition NodeId Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions ExternDefinition "extern_definition" 'S.Input
newtype InputRelation
= InputRelation Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions InputRelation "input_relation" 'S.Input
newtype OutputRelation
= OutputRelation Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions OutputRelation "output_relation" 'S.Input
newtype InternalRelation
= InternalRelation Id
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions InternalRelation "internal_relation" 'S.Input
newtype Module
= Module NodeId
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions Module "module" 'S.Input
data ModuleDecl
= ModuleDecl { moduleId :: NodeId, declId :: NodeId }
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions ModuleDecl "module_declaration" 'S.Input
data ScopedValue
= ScopedValue { svScopeId :: NodeId, svNodeId :: NodeId }
deriving stock Generic
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions ScopedValue "scoped_value" 'S.Input
data UngroundedVar loc
= UngroundedVar
{ ungroundedRuleLoc :: loc
, ungroundedVarLoc :: loc
, ungroundedVarName :: Id
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (UngroundedVar loc) "ungrounded_variable" 'S.Output
data WildcardInFact loc
= WildcardInFact
{ factLoc :: loc
, factArgLoc :: loc
, wildcardFactPos :: Position
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (WildcardInFact loc) "wildcard_in_fact" 'S.Output
data WildcardInRuleHead loc
= WildcardInRuleHead
{ wildcardRuleLoc :: loc
, wildcardRuleArgLoc :: loc
, wildcardRuleHeadPos :: Position
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (WildcardInRuleHead loc) "wildcard_in_rule_head" 'S.Output
data WildcardInConstraint loc
= WildcardInConstraint
{ wildcardConstraintLoc :: loc
, wildcardConstraintPos :: loc
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (WildcardInConstraint loc) "wildcard_in_constraint" 'S.Output
data WildcardInBinOp loc
= WildcardInBinOp
{ wildcardBinOpLoc :: loc
, wildcardBinOpPos :: loc
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (WildcardInBinOp loc) "wildcard_in_binop" 'S.Output
data WildcardInExtern loc
= WildcardInExtern
{ wildcardExternAtomLoc :: loc
, wildcardExternAtomArgLoc :: loc
, wildcardExternArgPos :: Position
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (WildcardInExtern loc) "wildcard_in_extern" 'S.Output
data UnconstrainedRuleVar loc
= UnconstrainedRuleVar
{ urvRuleLoc :: loc
, urvVarLoc :: loc
, urvVarName :: Id
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (UnconstrainedRuleVar loc) "unconstrained_rule_var" 'S.Output
newtype DeadCode
= DeadCode { unDeadCode :: NodeId }
deriving stock (Generic, Eq)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions DeadCode "dead_code" 'S.Output
newtype NoOutputRelation loc
= NoOutputRelation loc
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (NoOutputRelation loc) "no_output_relation" 'S.Output
data DeadInternalRelation loc
= DeadInternalRelation loc Id
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (DeadInternalRelation loc) "dead_internal_relation" 'S.Output
data ConflictingDefinitions loc
= ConflictingDefinitions
{ cdFirstLoc :: loc
, cdSecondLoc :: loc
, cdName :: Id
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (ConflictingDefinitions loc) "conflicting_definitions" 'S.Output
data ConflictingDefinitionGroup loc
= ConflictingDefinitionGroup
{ cdgName :: Id
, cdgLocs :: NonEmpty loc
} deriving stock (Eq, Functor)
data ExternUsedAsFact loc
= ExternUsedAsFact
{ externAsFactLoc :: loc
, externAsFactExternLoc :: loc
, externAsFactName :: Id
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (ExternUsedAsFact loc) "extern_used_as_fact" 'S.Output
data ExternUsedAsRule loc
= ExternUsedAsRule
{ externAsRuleLoc :: loc
, externAsRuleExternLoc :: loc
, externAsRuleName :: Id
}
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (ExternUsedAsRule loc) "extern_used_as_rule" 'S.Output
newtype CyclicNegation loc
= CyclicNegation loc
deriving stock (Generic, Eq, Functor)
deriving anyclass S.Marshal
deriving S.Fact via S.FactOptions (CyclicNegation loc) "cyclic_negation" 'S.Output
data SemanticAnalysis
= SemanticAnalysis
deriving S.Program
via S.ProgramOptions SemanticAnalysis "semantic_analysis"
'[ LitNumber
, LitString
, Var
, Hole
, Constraint
, BinOp
, Atom
, AtomArg
, Rule
, RuleArg
, RuleClause
, Negation
, DeclareType
, ExternDefinition
, InputRelation
, OutputRelation
, InternalRelation
, Module
, ModuleDecl
, ScopedValue
, UngroundedVar NodeId
, WildcardInRuleHead NodeId
, WildcardInFact NodeId
, WildcardInConstraint NodeId
, WildcardInBinOp NodeId
, WildcardInExtern NodeId
, UnconstrainedRuleVar NodeId
, DeadCode
, NoOutputRelation NodeId
, DeadInternalRelation NodeId
, ConflictingDefinitions NodeId
, ExternUsedAsFact NodeId
, ExternUsedAsRule NodeId
, CyclicNegation NodeId
]
-- TODO: change to Vector when finished for performance
type Container = []
newtype SemanticInfo
= SemanticInfo
{ deadCodeIds :: Container DeadCode
} deriving Eq
data Result
= Result
{ semanticInfo :: SemanticInfo
, semanticErrors :: SemanticErrors NodeId
}
deriving Eq
data SemanticErrors loc
= SemanticErrors
{ ungroundedVars :: Container (UngroundedVar loc)
, wildcardsInFacts :: Container (WildcardInFact loc)
, wildcardsInRuleHeads :: Container (WildcardInRuleHead loc)
, wildcardsInConstraints :: Container (WildcardInConstraint loc)
, wildcardsInBinOps :: Container (WildcardInBinOp loc)
, wildcardsInExternAtoms :: Container (WildcardInExtern loc)
, unconstrainedVars :: Container (UnconstrainedRuleVar loc)
, deadInternalRelations :: Container (DeadInternalRelation loc)
, noOutputRelations :: Container (NoOutputRelation loc)
, conflictingDefinitions :: Container (ConflictingDefinitionGroup loc)
, externsUsedAsFact :: Container (ExternUsedAsFact loc)
, externsUsedAsRule :: Container (ExternUsedAsRule loc)
, cyclicNegations :: Container (CyclicNegation loc)
}
deriving (Eq, Functor)
hasSemanticErrors :: Result -> Bool
hasSemanticErrors result =
isNotNull ungroundedVars ||
isNotNull wildcardsInFacts ||
isNotNull wildcardsInRuleHeads ||
isNotNull wildcardsInConstraints ||
isNotNull wildcardsInBinOps ||
isNotNull wildcardsInExternAtoms ||
isNotNull unconstrainedVars ||
isNotNull deadInternalRelations ||
isNotNull noOutputRelations ||
isNotNull conflictingDefinitions ||
isNotNull externsUsedAsFact ||
isNotNull cyclicNegations
where
errs = semanticErrors result
isNotNull :: (SemanticErrors NodeId -> [a]) -> Bool
isNotNull f = not . null $ f errs
analysis :: Word -> S.Handle SemanticAnalysis -> S.Analysis S.SouffleM IR.AST Result
analysis numCores prog = S.mkAnalysis addFacts run getFacts
where
addFacts :: IR.AST -> S.SouffleM ()
addFacts ast = usingReaderT Nothing $ flip (zygo IR.getNodeIdF) ast $ \case
IR.LitF nodeId lit -> do
mScopeId <- ask
for_ mScopeId $ \scopeId ->
S.addFact prog $ ScopedValue scopeId nodeId
case lit of
IR.LNumber x ->
S.addFact prog $ LitNumber nodeId x
IR.LString x ->
S.addFact prog $ LitString nodeId x
IR.PWildcardF nodeId ->
S.addFact prog $ Var nodeId (Id "_")
IR.VarF nodeId var -> do
S.addFact prog $ Var nodeId var
mScopeId <- ask
for_ mScopeId $ \scopeId ->
S.addFact prog $ ScopedValue scopeId nodeId
IR.HoleF nodeId ->
S.addFact prog $ Hole nodeId
IR.BinOpF nodeId arithOp (lhsId', lhsAction) (rhsId', rhsAction) -> do
let textualOp = case arithOp of
IR.Plus -> "+"
IR.Minus -> "-"
IR.Multiply -> "*"
IR.Divide -> "/"
mScopeId <- ask
for_ mScopeId $ \scopeId ->
S.addFact prog $ ScopedValue scopeId nodeId
S.addFact prog $ BinOp nodeId textualOp lhsId' rhsId'
lhsAction
rhsAction
IR.ConstraintF nodeId constraintOp (lhsId', lhsAction) (rhsId', rhsAction) -> do
let textualOp = case constraintOp of
IR.Equals -> "="
IR.NotEquals -> "!="
IR.LessThan -> "<"
IR.LessOrEqual -> "<="
IR.GreaterThan -> "<"
IR.GreaterOrEqual -> "<="
S.addFact prog $ Constraint nodeId textualOp lhsId' rhsId'
lhsAction
rhsAction
IR.NotF nodeId (innerNodeId, action) -> do
S.addFact prog $ Negation nodeId innerNodeId
local (const $ Just nodeId) action
IR.AtomF nodeId atom (unzip -> (argNodeIds, actions)) -> do
S.addFact prog $ Atom nodeId atom
mScopeId <- ask
S.addFacts prog $ mapWithPos (AtomArg nodeId) argNodeIds
for_ mScopeId $ \scopeId ->
S.addFact prog $ ScopedValue scopeId nodeId
let maybeAddScope =
if isJust mScopeId
then id
else local (const $ Just nodeId)
maybeAddScope $ sequence_ actions
IR.RuleF nodeId rule ruleArgs ruleClauses -> do
let (argNodeIds, argActions) = unzip ruleArgs
(clauseNodeIds, clauseActions) = unzip ruleClauses
S.addFact prog $ Rule nodeId rule
S.addFacts prog $ mapWithPos (RuleArg nodeId) argNodeIds
S.addFacts prog $ mapWithPos (RuleClause nodeId) clauseNodeIds
local (const $ Just nodeId) $ do
sequence_ argActions
sequence_ clauseActions
IR.ExternDefinitionF nodeId name _ _ -> do
S.addFact prog $ ExternDefinition nodeId name
IR.DeclareTypeF nodeId name _ usageMode -> do
S.addFact prog $ DeclareType nodeId name
case usageMode of
IR.Input ->
S.addFact prog $ InputRelation name
IR.Output ->
S.addFact prog $ OutputRelation name
IR.InputOutput -> do
S.addFact prog $ InputRelation name
S.addFact prog $ OutputRelation name
IR.Internal ->
S.addFact prog $ InternalRelation name
IR.ModuleF nodeId (unzip -> (declNodeIds, actions)) -> do
S.addFact prog $ Module nodeId
S.addFacts prog $ map (ModuleDecl nodeId) declNodeIds
sequence_ actions
run :: S.SouffleM ()
run = do
S.setNumThreads prog (fromIntegral numCores)
S.run prog
getFacts :: S.SouffleM Result
getFacts = do
info <- SemanticInfo <$> S.getFacts prog
errs <- SemanticErrors <$> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
<*> (groupConflicts <$> S.getFacts prog)
<*> S.getFacts prog
<*> S.getFacts prog
<*> S.getFacts prog
pure $ Result info errs
mapWithPos :: (Word32 -> a -> b) -> [a] -> [b]
mapWithPos g = zipWith g [0..]
groupConflicts :: Container (ConflictingDefinitions NodeId) -> Container (ConflictingDefinitionGroup NodeId)
groupConflicts conflicts =
conflicts
& sortWith sameConflict
& groupBy ((==) `on` sameConflict)
& map (\cg ->
let firstConflict = head cg
declName = cdName firstConflict
locs = NE.cons (cdFirstLoc firstConflict) (map cdSecondLoc cg)
in ConflictingDefinitionGroup declName locs
)
& nubOrdOn cdgName
where
sameConflict = cdName &&& cdFirstLoc
runAnalysis :: Word -> IR.AST -> IO Result
runAnalysis numCores ast = S.runSouffle SemanticAnalysis $ \case
Nothing -> panic "Failed to load Souffle during semantic analysis!"
Just prog -> S.execAnalysis (analysis numCores prog) ast
computeUsageMapping :: IR.AST -> Map Id IR.UsageMode
computeUsageMapping ast =
Map.fromList pairs
where
pairs = flip cata ast $ \case
IR.DeclareTypeF _ name _ mode ->
one (name, mode)
astf ->
fold astf
================================================
FILE: lib/Eclair/AST/Codegen.hs
================================================
{-# LANGUAGE DerivingVia #-}
module Eclair.AST.Codegen
( CodegenM
, Env(..)
, runCodegen
, toTerm
, project
, search
, loop
, parallel
, merge
, swap
, purge
, exit
, noElemOf
, if'
) where
import Prelude hiding (swap, project)
import Data.DList (DList)
import qualified Data.DList as DList
import qualified Eclair.RA.IR as RA
import qualified Eclair.AST.IR as AST
import Eclair.Common.Location
import Eclair.Common.Literal
import Eclair.Common.Operator
import Eclair.Common.Id
import Eclair.Common.Extern
type AST = AST.AST
type RA = RA.RA
type Relation = RA.Relation
type Alias = RA.Alias
type Variable = Id
type Column = Int
newtype Row = Row { unRow :: Int }
deriving (Eq, Ord)
data InLoop
= InLoop
deriving Eq
data Env
= Env
{ envRow :: Row
, envExterns :: [Extern]
, envLoopContext :: Maybe InLoop
}
data LowerState
= LowerState
{ nextNodeId :: Word32 -- NOTE: Unrelated to NodeIDs used in AST!
-- Constraints that can be resolved directly, but need to be emitted later.
, directConstraints :: CodegenM RA -> CodegenM RA
-- We keep track of which alias + column maps to which variables for later
-- generation of constraints.
, varMapping :: DList (Alias, Column, Variable)
}
newtype CodegenM a
= CodegenM (RWS Env () LowerState a)
deriving (Functor, Applicative, Monad, MonadReader Env, MonadState LowerState)
via RWS Env () LowerState
runCodegen :: [Extern] -> CodegenM a -> a
runCodegen externs (CodegenM m) =
-- NOTE: NodeId starts at 1, since module is manually created, and has NodeId 0
let beginState = LowerState 1 id mempty
in fst $ evalRWS m (Env (Row 0) externs Nothing) beginState
freshNodeId :: CodegenM NodeId
freshNodeId = do
next <- gets nextNodeId
modify $ \s -> s { nextNodeId = next + 1 }
pure $ NodeId next
project :: Relation -> [CodegenM RA] -> CodegenM RA
project r terms = do
nodeId <- freshNodeId
(addDirectConstraints, mapping) <- gets (directConstraints &&& varMapping)
let grouped =
mapping
& toList
& sortOn varNameOf
& groupBy ((==) `on` varNameOf)
eqs = map toIndirectConstraint grouped
addIndirectConstraints = foldl' (.) id eqs
noElemConstraint <- lookupNoElemConstraint
addDirectConstraints . addIndirectConstraints . noElemConstraint $
RA.Project nodeId r <$> sequence terms
where
varNameOf (_, _, v) = v
resolveAliasValue (a, col, _) = do
nodeId <- freshNodeId
pure $ RA.ColumnIndex nodeId a col
toIndirectConstraint bindingGroup m = case bindingGroup of
initial :| rest -> do
aliasValue <- resolveAliasValue initial
aliasValues <- traverse resolveAliasValue rest
let constraints = map (if' Equals aliasValue) aliasValues
wrapConstraints = foldl' (.) id constraints
wrapConstraints m
lookupNoElemConstraint = do
loopCtx <- asks envLoopContext
if loopCtx == Just InLoop
then pure $ noElemOf (stripIdPrefixes r) terms
else pure id
search :: Relation -> [AST] -> CodegenM RA -> CodegenM RA
search r terms inner = do
nodeId <- freshNodeId
-- Potentially reset var mapping when we reach the first search,
-- this makes it possible to easily support multiple project statements.
maybeResetSearchState
a <- relationToAlias r
zipWithM_ (\col t -> emitSearchTerm t a col) [0..] terms
action <- local nextRow inner
pure $ RA.Search nodeId r a [] action
where
nextRow s = s { envRow = Row . (+1) . unRow $ envRow s }
maybeResetSearchState = do
Row row <- asks envRow
when (row == 0) $ do
modify $ \s -> s { varMapping = mempty }
emitSearchTerm :: AST -> Alias -> Column -> CodegenM ()
emitSearchTerm ast a col = do
-- Based on what the term resolved to, we might need to create additional
-- constraints. Literals can directly be converted to a constraint, variables
-- are solved at the end (in the project statement).
case ast of
AST.Lit {} ->
addDirectConstraint ast a col
AST.BinOp {} ->
addDirectConstraint ast a col
AST.PWildcard _ ->
pass
AST.Var _ v ->
-- We append new constraints at the end.
-- This will cause indices to always trigger as soon as possible,
-- which narrows down the search space and speeds up the query.
modify $ \s -> s { varMapping = DList.snoc (varMapping s) (a, col, v) }
_ ->
pass
addDirectConstraint ast a col = do
ra <- toTerm ast
nodeId <- freshNodeId
let aliasValue = RA.ColumnIndex nodeId a col
constraint = if' Equals aliasValue ra
modify $ \s -> s { directConstraints = directConstraints s . constraint }
loop :: [CodegenM RA] -> CodegenM RA
loop ms = local (\env -> env { envLoopContext = Just InLoop}) $ do
nodeId <- freshNodeId
RA.Loop nodeId <$> sequence ms
parallel :: [CodegenM RA] -> CodegenM RA
parallel = \case
[m] -> m
ms -> do
nodeId <- freshNodeId
RA.Par nodeId <$> sequence ms
merge :: Relation -> Relation -> CodegenM RA
merge from' to' = do
nodeId <- freshNodeId
pure $ RA.Merge nodeId from' to'
swap :: Relation -> Relation -> CodegenM RA
swap r1 r2 = do
nodeId <- freshNodeId
pure $ RA.Swap nodeId r1 r2
purge :: Relation -> CodegenM RA
purge r = do
nodeId <- freshNodeId
pure $ RA.Purge nodeId r
exit :: [Relation] -> CodegenM RA
exit rs = do
nodeId <- freshNodeId
pure $ RA.Exit nodeId rs
noElemOf :: Relation -> [CodegenM RA] -> CodegenM RA -> CodegenM RA
noElemOf r ts inner = do
notElemNodeId <- freshNodeId
ifNodeId <- freshNodeId
cond <- RA.NotElem notElemNodeId r <$> sequence ts
RA.If ifNodeId cond <$> inner
if' :: LogicalOp -> RA -> RA -> CodegenM RA -> CodegenM RA
if' op lhs rhs body = do
cmpNodeId <- freshNodeId
ifNodeId <- freshNodeId
let cond = RA.CompareOp cmpNodeId op lhs rhs
RA.If ifNodeId cond <$> body
toTerm :: AST -> CodegenM RA
toTerm ast = do
nodeId <- freshNodeId
case ast of
AST.Lit _ (LNumber lit) ->
pure $ RA.Lit nodeId lit
AST.PWildcard _ ->
pure $ RA.Undef nodeId
AST.Var _ v -> do
gets (find (\(_, _, v') -> v == v') . varMapping) >>= \case
Just (alias, col, _) -> do
pure $ RA.ColumnIndex nodeId alias col
Nothing ->
panic $ "Found ungrounded variable '" <> unId v <> "' in 'toTerm'!"
AST.BinOp _ op lhs rhs -> do
lhsTerm <- toTerm lhs
rhsTerm <- toTerm rhs
pure $ RA.PrimOp nodeId (RA.BuiltinOp op) [lhsTerm, rhsTerm]
AST.Atom _ name args -> do
RA.PrimOp nodeId (RA.ExternOp name) <$> traverse toTerm args
_ ->
panic "Unexpected case in 'toTerm'!"
relationToAlias :: Relation -> CodegenM Alias
relationToAlias r =
asks (appendToId r . show . unRow . envRow)
================================================
FILE: lib/Eclair/AST/IR.hs
================================================
{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}
module Eclair.AST.IR
( AST(.., PWildcard)
, ASTF(.., PWildcardF)
, Value
, Clause
, Decl
, Literal(..)
, Type(..)
, ArithmeticOp(..)
, LogicalOp(..)
, isEqualityOp
, getNodeId
, getNodeIdF
, getExternDefs
, UsageMode(..)
, Attributes
) where
import Prettyprinter
import Eclair.Common.Id
import Eclair.Common.Operator
import Eclair.Common.Extern
import Eclair.Common.Literal
import Eclair.Common.Pretty
import Eclair.Common.Location
type Value = AST
type Clause = AST
type Decl = AST
data Type
= U32
| Str
| TUnknown Int -- NOTE: unification variable, only used internally!
deriving (Eq, Ord, Show)
data UsageMode
= Input
| Output
| InputOutput
| Internal -- This variant is only used internally (pun intended).
deriving (Eq, Show)
-- Later this will also contain (Maybe StorageType), ...
type Attributes = UsageMode
-- NOTE: There is no explicit "AND" node, conjunctions are inlined into other
-- nodes (as lists of clauses).
data AST
-- Expressions
= Lit NodeId Literal
| Var NodeId Id
| Hole NodeId
| BinOp NodeId ArithmeticOp AST AST
-- Statements
| Constraint NodeId LogicalOp AST AST
| Rule NodeId Id [Value] [Clause]
| Not NodeId Clause
| Atom NodeId Id [Value] -- Can be both a Datalog relation, or a externally defined function / constraint
| ExternDefinition NodeId Id [(Maybe Id, Type)] (Maybe Type)
| DeclareType NodeId Id [(Maybe Id, Type)] Attributes
| Module NodeId [Decl]
deriving (Eq, Show)
pattern PWildcard :: NodeId -> AST
pattern PWildcard nodeId
= Var nodeId (Id "_")
makeBaseFunctor ''AST
pattern PWildcardF :: NodeId -> ASTF r
pattern PWildcardF nodeId
= VarF nodeId (Id "_")
getNodeId :: AST -> NodeId
getNodeId = \case
Module nodeId _ -> nodeId
DeclareType nodeId _ _ _ -> nodeId
ExternDefinition nodeId _ _ _ -> nodeId
Rule nodeId _ _ _ -> nodeId
Not nodeId _ -> nodeId
Atom nodeId _ _ -> nodeId
BinOp nodeId _ _ _ -> nodeId
Constraint nodeId _ _ _ -> nodeId
Lit nodeId _ -> nodeId
Var nodeId _ -> nodeId
Hole nodeId -> nodeId
getNodeIdF :: ASTF a -> NodeId
getNodeIdF = \case
ModuleF nodeId _ -> nodeId
DeclareTypeF nodeId _ _ _ -> nodeId
ExternDefinitionF nodeId _ _ _ -> nodeId
RuleF nodeId _ _ _ -> nodeId
NotF nodeId _ -> nodeId
AtomF nodeId _ _ -> nodeId
BinOpF nodeId _ _ _ -> nodeId
ConstraintF nodeId _ _ _ -> nodeId
LitF nodeId _ -> nodeId
VarF nodeId _ -> nodeId
HoleF nodeId -> nodeId
getExternDefs :: AST -> [Extern]
getExternDefs = cata $ \case
ExternDefinitionF _ name argTys mRetTy ->
let extKind = if isJust mRetTy then ExternFunction else ExternConstraint
in one $ Extern name (length argTys) extKind
astf ->
fold astf
instance Pretty Type where
pretty = \case
U32 -> "u32"
Str -> "string"
TUnknown x -> "ty" <> show x
data RenderPosition = TopLevel | Nested
instance Pretty AST where
pretty ast = runReader (pretty' ast) TopLevel
where
pretty' = \case
Lit _ x ->
pure $ pretty x
Var _ v ->
pure $ pretty v
Hole _ ->
pure "?"
BinOp _ op lhs rhs -> do
lhs' <- pretty' lhs
rhs' <- pretty' rhs
pure $ parens $ lhs' <+> pretty op <+> rhs'
Constraint _ op lhs rhs -> do
lhs' <- pretty' lhs
rhs' <- pretty' rhs
pure $ lhs' <+> pretty op <+> rhs'
Not _ clause ->
("!" <>) <$> pretty' clause
Atom _ name values -> do
end <- ask <&> \case
TopLevel -> "."
Nested -> mempty
values' <- traverse pretty' values
pure $ pretty name <> parens (withCommas values') <> end
Rule _ name values clauses -> do
(values', clauses') <- local (const Nested) $ do
(,) <$> traverse pretty' values <*> traverse pretty' clauses
let separators = replicate (length clauses - 1) "," ++ ["."]
pure $ pretty name <> parens (withCommas values') <+> ":-" <> hardline <>
indent 2 (vsep (zipWith (<>) clauses' separators))
ExternDefinition _ name args mRetTy -> do
let prettyRetTy = case mRetTy of
Just retTy -> " " <> pretty retTy
Nothing -> mempty
pure $ "@extern" <+> pretty name <> parens (withCommas $ map prettyArg args)
<> prettyRetTy <> "."
DeclareType _ name tys attrs ->
pure $ "@def"
<+> pretty name
<> parens (withCommas $ map prettyArg tys)
<> prettyAttrs
<> "."
where
prettyAttrs = case attrs of
Internal -> ""
Input -> " input"
Output -> " output"
InputOutput -> " input output"
Module _ decls -> do
decls' <- traverse pretty' decls
pure $ vsep $ intersperse mempty decls'
prettyArg (mName, ty) =
maybe (pretty ty) (\fieldName -> pretty fieldName <> ":" <+> pretty ty) mName
================================================
FILE: lib/Eclair/AST/Lower.hs
================================================
module Eclair.AST.Lower
( compileToRA
) where
import Prelude hiding (swap, project)
import qualified Data.Graph as G
import qualified Data.Map as M
import Eclair.AST.Codegen
import Eclair.AST.IR hiding (Clause)
import Eclair.Common.Id
import Eclair.Common.Location (NodeId(..))
import qualified Eclair.RA.IR as RA
import Eclair.Common.Extern
type RA = RA.RA
type Relation = RA.Relation
compileToRA :: [Extern] -> AST -> RA
compileToRA externs ast =
RA.Module (NodeId 0) $ concatMap processDecls sortedDecls
where
sortedDecls = scc ast
processDecls :: [AST] -> [RA]
processDecls = \case
[Atom _ name values] -> runCodegen externs $
let literals = map toTerm values
in one <$> project name literals
[Rule _ name args clauses] ->
let terms = map toTerm args
in runCodegen externs $ processSingleRule [name] name terms clauses
rules -> -- case for multiple mutually recursive rules
let sccNames = rules & mapMaybe (\case
Rule _ name _ _ -> Just name
_ -> Nothing)
in runCodegen externs $ processMultipleRules sccNames rules
scc :: AST -> [[AST]]
scc = \case
Module _ decls -> map G.flattenSCC sortedDecls'
where
relevantDecls = filter isRelevant decls
sortedDecls' = G.stronglyConnComp $ zipWith (\i d -> (d, i, refersTo d)) [0..] relevantDecls
declLineMapping = M.fromListWith (<>) $ zipWith (\i d -> (nameFor d, [i])) [0..] relevantDecls
isRelevant = \case
Atom {} -> True
Rule {} -> True
Not {} -> True
_ -> False
nameFor = \case
Atom _ name _ -> name
Rule _ name _ _ -> name
_ -> unreachable -- Because of "isRelevant"
refersTo :: AST -> [Int]
refersTo = \case
Rule _ _ _ clauses ->
-- If no top level facts are defined, no entry exists in declLine mapping -> default to -1
concatMap (fromMaybe [-1] . flip M.lookup declLineMapping . dependsOn) $ filter isRelevant clauses
_ -> []
dependsOn = \case
Atom _ name _ -> name
Rule _ name _ _ -> name
Not _ (Atom _ name _) -> name
_ -> unreachable -- Because of "isRelevant"
_ -> unreachable -- Because rejected by parser
where unreachable = panic "Unreachable code in 'scc'"
-- NOTE: These rules can all be evaluated in parallel inside the fixpoint loop
processMultipleRules :: [Relation] -> [AST] -> CodegenM [RA]
processMultipleRules sccNames rules = sequence stmts where
stmts = mergeStmts <> [loop (purgeStmts <> ruleStmts <> [exitStmt] <> endLoopStmts)]
mergeStmts = map (\r -> merge r (deltaRelationOf r)) uniqRelations
purgeStmts = map (purge . newRelationOf) uniqRelations
ruleStmts = [parallel $ map lowerRule rulesInfo]
exitStmt = exit $ map newRelationOf uniqRelations
endLoopStmts = concatMap toMergeAndSwapStmts uniqRelations
toMergeAndSwapStmts r =
let newRelation = newRelationOf r
deltaRelation = deltaRelationOf r
in [merge newRelation r, swap newRelation deltaRelation]
rulesInfo = mapMaybe extractRuleData rules
relations = map (\(r, _, _) -> r) rulesInfo
uniqRelations = uniqOrderPreserving relations
-- TODO: better func name
lowerRule (r, map toTerm -> ts, clauses) =
recursiveRuleToStmts sccNames r ts clauses
processSingleRule :: [Relation] -> Relation -> [CodegenM RA] -> [AST] -> CodegenM [RA]
processSingleRule sccNames relation terms clauses
| isRecursive sccNames clauses =
let deltaRelation = deltaRelationOf relation
newRelation = newRelationOf relation
stmts =
[ merge relation deltaRelation
, loop
[ purge newRelation
, ruleToStmt sccNames relation terms clauses
, exit [newRelation]
, merge newRelation relation
, swap newRelation deltaRelation
]
]
in sequence stmts
| otherwise = one <$> ruleToStmt sccNames relation terms clauses
ruleToStmt :: [Relation] -> Relation -> [CodegenM RA] -> [AST] -> CodegenM RA
ruleToStmt sccNames relation terms clauses
| isRecursive sccNames clauses =
recursiveRuleToStmts sccNames relation terms clauses
| otherwise = nestedSearchAndProject relation terms clauses mempty
recursiveRuleToStmts :: [Relation] -> Relation -> [CodegenM RA] -> [AST] -> CodegenM RA
recursiveRuleToStmts sccNames relation terms clauses =
parallel $
[ stmt
| i <- [0..sccClauseCount - 1]
, let sccAtom = maybeAt i sccAtoms
clauses' = map (maybeToDeltaClause sccAtom) clauses
sccAtoms' = drop (i + 1) sccAtoms
stmt = nestedSearchAndProject newRelation terms clauses' sccAtoms'
]
where
newRelation = newRelationOf relation
sccAtoms = clauses & filter isPartOfScc & mapMaybe (\case
Atom _ name args -> Just (name, args)
_ -> Nothing)
sccClauseCount = length sccAtoms
isPartOfScc = \case
Atom _ name _ -> name `elem` sccNames
_ -> False
maybeToDeltaClause sccAtom = \case
Atom nodeId clauseName args | sccAtom == Just (clauseName, args) ->
Atom nodeId (deltaRelationOf clauseName) args
clause -> clause
nestedSearchAndProject
:: Relation
-> [CodegenM RA]
-> [AST]
-> [(Relation, [AST])]
-> CodegenM RA
nestedSearchAndProject intoRelation terms clauses sccAtoms =
flip (foldr processRuleClause) clauses $
addNegatedDeltaAtoms sccAtoms $
project intoRelation terms
where
processRuleClause :: AST -> CodegenM RA -> CodegenM RA
processRuleClause clause inner = case clause of
Not _ (Atom _ clauseName args) -> do
-- No starts with check here, since cyclic negation is not allowed.
let terms' = map toTerm args
noElemOf clauseName terms' inner
Constraint _ op lhs rhs -> do
lhsTerm <- toTerm lhs
rhsTerm <- toTerm rhs
if' op lhsTerm rhsTerm inner
Atom _ clauseName args -> do
externs <- asks envExterns
let isExtern = isJust $ find (\(Extern name _ _) -> clauseName == name) externs
if isExtern
then do
clause' <- toTerm clause
zero <- toTerm (Lit (NodeId 0) $ LNumber 0)
if' NotEquals clause' zero inner
else search clauseName args inner
_ ->
panic "Unexpected rule clause in 'nestedSearchAndProject'!"
addNegatedDeltaAtoms =
foldr (\(clauseName, args) wrapper -> wrapper . addNegatedDeltaAtom clauseName args) id
addNegatedDeltaAtom :: Relation -> [AST] -> CodegenM RA -> CodegenM RA
addNegatedDeltaAtom clauseName args =
noElemOf (deltaRelationOf clauseName) (map toTerm args)
isRecursive :: [Relation] -> [AST] -> Bool
isRecursive sccNames clauses =
let atomNames = flip mapMaybe clauses $ \case
Atom _ name _ -> Just name
_ -> Nothing
in any (`elem` atomNames) sccNames
extractRuleData :: AST -> Maybe (Relation, [AST], [AST])
extractRuleData = \case
Rule _ name args clauses -> Just (name, args, clauses)
_ -> Nothing
newRelationOf, deltaRelationOf :: Relation -> Relation
deltaRelationOf = prependToId deltaPrefix
newRelationOf = prependToId newPrefix
================================================
FILE: lib/Eclair/AST/Transforms/ConstantFolding.hs
================================================
module Eclair.AST.Transforms.ConstantFolding
( transform
) where
import Eclair.AST.IR
import Eclair.Transform
transform :: Transform AST AST
transform = pureTransform $ cata $ \case
BinOpF nodeId op (Lit _ (LNumber lhs)) (Lit _ (LNumber rhs)) ->
let opFn = case op of
Plus -> (+)
Minus -> (-)
Multiply -> (*)
Divide -> div
in Lit nodeId $ LNumber $ opFn lhs rhs
ast ->
embed ast
================================================
FILE: lib/Eclair/AST/Transforms/DeadCodeElimination.hs
================================================
module Eclair.AST.Transforms.DeadCodeElimination
( tr
gitextract_d5o1d0tz/
├── .dockerignore
├── .ghci
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── build.yml
│ └── ci.yml
├── .gitignore
├── .hlint.yaml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cabal.project
├── cbits/
│ └── semantic_analysis.dl
├── docs/
│ ├── architecture_choices.md
│ └── getting_started.md
├── eclair-lang.cabal
├── hie.yaml
├── lib/
│ ├── Eclair/
│ │ ├── AST/
│ │ │ ├── Analysis.hs
│ │ │ ├── Codegen.hs
│ │ │ ├── IR.hs
│ │ │ ├── Lower.hs
│ │ │ ├── Transforms/
│ │ │ │ ├── ConstantFolding.hs
│ │ │ │ ├── DeadCodeElimination.hs
│ │ │ │ ├── NormalizeRules.hs
│ │ │ │ ├── RemoveAliases.hs
│ │ │ │ └── ReplaceStrings.hs
│ │ │ └── Transforms.hs
│ │ ├── ArgParser.hs
│ │ ├── Common/
│ │ │ ├── Config.hs
│ │ │ ├── Extern.hs
│ │ │ ├── Id.hs
│ │ │ ├── Literal.hs
│ │ │ ├── Location.hs
│ │ │ ├── Operator.hs
│ │ │ └── Pretty.hs
│ │ ├── Comonads.hs
│ │ ├── EIR/
│ │ │ ├── IR.hs
│ │ │ ├── Lower/
│ │ │ │ ├── API.hs
│ │ │ │ ├── Codegen.hs
│ │ │ │ └── Externals.hs
│ │ │ └── Lower.hs
│ │ ├── Error.hs
│ │ ├── JSON.hs
│ │ ├── LLVM/
│ │ │ ├── Allocator/
│ │ │ │ ├── Arena.hs
│ │ │ │ ├── Common.hs
│ │ │ │ ├── Malloc.hs
│ │ │ │ └── Page.hs
│ │ │ ├── BTree/
│ │ │ │ ├── Bounds.hs
│ │ │ │ ├── Compare.hs
│ │ │ │ ├── Create.hs
│ │ │ │ ├── Destroy.hs
│ │ │ │ ├── Find.hs
│ │ │ │ ├── Insert.hs
│ │ │ │ ├── Iterator.hs
│ │ │ │ ├── Size.hs
│ │ │ │ └── Types.hs
│ │ │ ├── BTree.hs
│ │ │ ├── Codegen.hs
│ │ │ ├── Config.hs
│ │ │ ├── Externals.hs
│ │ │ ├── Hash.hs
│ │ │ ├── HashMap.hs
│ │ │ ├── Metadata.hs
│ │ │ ├── Symbol.hs
│ │ │ ├── SymbolTable.hs
│ │ │ ├── Table.hs
│ │ │ ├── Template.hs
│ │ │ └── Vector.hs
│ │ ├── LSP/
│ │ │ ├── Handlers/
│ │ │ │ ├── Diagnostics.hs
│ │ │ │ ├── DocumentHighlight.hs
│ │ │ │ └── Hover.hs
│ │ │ ├── Handlers.hs
│ │ │ ├── JSON.hs
│ │ │ ├── Monad.hs
│ │ │ ├── Types.hs
│ │ │ └── VFS.hs
│ │ ├── LSP.hs
│ │ ├── Parser.hs
│ │ ├── RA/
│ │ │ ├── Codegen.hs
│ │ │ ├── IR.hs
│ │ │ ├── IndexSelection.hs
│ │ │ ├── Lower.hs
│ │ │ ├── Transforms/
│ │ │ │ └── HoistConstraints.hs
│ │ │ └── Transforms.hs
│ │ ├── Souffle/
│ │ │ └── IR.hs
│ │ ├── Transform.hs
│ │ └── TypeSystem.hs
│ ├── Eclair.hs
│ └── Prelude.hs
├── src/
│ └── eclair/
│ └── Main.hs
└── tests/
├── .gitignore
├── ast_transforms/
│ ├── constant_folding.eclair
│ ├── copy_propagation.eclair
│ ├── dead_code_elimination.eclair
│ ├── remove_contradictions.eclair
│ └── shift_assignments.eclair
├── check.sh
├── eclair/
│ ├── Test/
│ │ └── Eclair/
│ │ ├── ArgParserSpec.hs
│ │ ├── JSONSpec.hs
│ │ ├── LLVM/
│ │ │ ├── Allocator/
│ │ │ │ ├── MallocSpec.hs
│ │ │ │ ├── PageSpec.hs
│ │ │ │ └── Utils.hs
│ │ │ ├── BTreeSpec.hs
│ │ │ ├── HashMapSpec.hs
│ │ │ ├── HashSpec.hs
│ │ │ ├── SymbolSpec.hs
│ │ │ ├── SymbolTableSpec.hs
│ │ │ ├── SymbolUtils.hs
│ │ │ └── VectorSpec.hs
│ │ ├── LSP/
│ │ │ ├── HandlersSpec.hs
│ │ │ └── JSONSpec.hs
│ │ └── RA/
│ │ └── IndexSelectionSpec.hs
│ ├── fixtures/
│ │ └── lsp/
│ │ ├── document_highlight.eclair
│ │ ├── hover.eclair
│ │ ├── invalid_syntax.eclair
│ │ ├── semantic_errors.eclair
│ │ ├── type_errors.eclair
│ │ └── unparsable.eclair
│ └── test.hs
├── end_to_end/
│ ├── compile_and_run_native.eclair
│ ├── compile_and_run_wasm.eclair
│ └── compile_and_run_with_extern.eclair
├── hello.eclair
├── lit.cfg
├── lowering/
│ ├── arithmetic.eclair
│ ├── clause_with_same_vars.eclair
│ ├── comparisons.eclair
│ ├── different_types.eclair
│ ├── extern_definitions.eclair
│ ├── multiple_clauses_same_name.eclair
│ ├── multiple_rule_clauses.eclair
│ ├── mutually_recursive_rules.eclair
│ ├── negation.eclair
│ ├── negation_with_wildcards.eclair
│ ├── no_top_level_facts.eclair
│ ├── recursive_mix_of_rules.eclair
│ ├── single_non_recursive_rule.eclair
│ ├── single_recursive_rule.eclair
│ ├── stratification.eclair
│ ├── top_level_facts.eclair
│ └── wasm_codegen.eclair
├── parser/
│ ├── error_recovery.eclair
│ ├── file_not_found.eclair
│ └── valid.eclair
├── runtime/
│ ├── hashmap_test.eclair
│ ├── symbol_table_test.eclair
│ └── vector_test.eclair
├── semantic_analysis/
│ ├── cyclic_negation.eclair
│ ├── dead_internal_relation.eclair
│ ├── invalid_extern_usage.eclair
│ ├── invalid_options_usage.eclair
│ ├── invalid_wildcard_usage.eclair
│ ├── no_output_relations.eclair
│ ├── unconstrained_variables.eclair
│ ├── ungrounded_variables.eclair
│ ├── ungrounded_variables_arithmetic.eclair
│ ├── ungrounded_variables_comparisons.eclair
│ └── ungrounded_variables_negations.eclair
├── string_support/
│ ├── encode_decode_string.eclair
│ ├── encode_decode_string_native.eclair
│ └── encode_decode_string_wasm.eclair
├── transpilation/
│ └── souffle.eclair
├── typesystem/
│ ├── arg_count_mismatch.eclair
│ ├── arithmetic.eclair
│ ├── comparisons.eclair
│ ├── duplicate_type_declarations.eclair
│ ├── extern_definitions.eclair
│ ├── negation.eclair
│ ├── no_rules_for_type.eclair
│ ├── type_mismatch_in_rule.eclair
│ ├── type_mismatch_in_rule_body.eclair
│ ├── type_mismatch_in_rule_head.eclair
│ ├── type_mismatch_top_level_atoms.eclair
│ ├── typed_holes.eclair
│ ├── unification_failure.eclair
│ ├── unknown_atom_in_rule_body.eclair
│ ├── unknown_atom_in_rule_head.eclair
│ ├── unknown_atoms.eclair
│ ├── unknown_top_level_atoms.eclair
│ └── valid.eclair
└── utils/
└── extract_snippet
Condensed preview — 183 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (938K chars).
[
{
"path": ".dockerignore",
"chars": 165,
"preview": ".direnv/\n.git/\n.github/\ndist/\ndist-newstyle/\nresult/\nDockerfile\n.dockerignore\n.envrc\n.ghci\n.gitignore\n./*.ll\n./*.o\n./*.a"
},
{
"path": ".ghci",
"chars": 14,
"preview": ":set prompt >\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 19,
"preview": "github: luc-tielen\n"
},
{
"path": ".github/workflows/build.yml",
"chars": 781,
"preview": "name: \"Build\"\non: [push, pull_request]\njobs:\n build:\n strategy:\n matrix:\n os: [ubuntu-latest]\n runs-o"
},
{
"path": ".github/workflows/ci.yml",
"chars": 438,
"preview": "name: lint\non:\n pull_request:\n push:\n branches:\n - main\n - \"releases/*\"\njobs:\n hlint:\n runs-on: ubunt"
},
{
"path": ".gitignore",
"chars": 212,
"preview": "dist-newstyle/\ndist/\n.direnv/\n.devcontainer/\ncabal.project.local*\n\n*.ll\n*.bc\n*.o\n*.a\n*.s\n/*.wasm\n/*.dl\n/*.eclair\n/*.js\n\n"
},
{
"path": ".hlint.yaml",
"chars": 98776,
"preview": "# HLint configuration file\n# https://github.com/ndmitchell/hlint\n##########################\n\n# This file contains a temp"
},
{
"path": "CHANGELOG.md",
"chars": 2074,
"preview": "# Changelog\n\nAll notable changes to this project (as seen by library users) will be documented in this file.\nThe CHANGEL"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 4406,
"preview": "# Code of Conduct\n\nContact: luc.tielen@gmail.com\n\n## Why have a Code of Conduct?\n\nAs contributors and maintainers of thi"
},
{
"path": "Dockerfile",
"chars": 2415,
"preview": "FROM primordus/souffle-ubuntu:2.3\nARG LLVM_VERSION=17\n\nSHELL [ \"/bin/bash\", \"-c\" ]\n\n# install packages\nRUN echo 'tzdata "
},
{
"path": "LICENSE",
"chars": 1517,
"preview": "Copyright Luc Tielen (c) 2022\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\n"
},
{
"path": "Makefile",
"chars": 282,
"preview": "build: configure\n\t@cabal build\n\nconfigure:\n\t@cabal configure -f eclair-debug --enable-tests\n\nclean:\n\t@cabal clean\n\ntest:"
},
{
"path": "README.md",
"chars": 5482,
"preview": "<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"./logo_dark.png\"/>\n <img\n src=\"./logo_light.png\"\n "
},
{
"path": "cabal.project",
"chars": 467,
"preview": "packages: .\n\nsource-repository-package\n type: git\n location: https://github.com/luc-tielen/llvm-codegen.git\n ta"
},
{
"path": "cbits/semantic_analysis.dl",
"chars": 17796,
"preview": "// Input facts\n.decl lit_number(node_id: unsigned, value: unsigned)\n.decl lit_string(node_id: unsigned, value: symbol)\n."
},
{
"path": "docs/architecture_choices.md",
"chars": 9309,
"preview": "# Architecture choices\n\nThis document contains all the high level choices that have been made with\nregards to the archit"
},
{
"path": "docs/getting_started.md",
"chars": 4886,
"preview": "# Getting started\n\nEclair requires a Haskell toolchain, Souffle 2.3 and LLVM 14 to be installed on\nyour system.\n\nIf you "
},
{
"path": "eclair-lang.cabal",
"chars": 10499,
"preview": "cabal-version: 2.2\nname: eclair-lang\nversion: 0.2.0\nsynopsis:\n Eclair: an experimental an"
},
{
"path": "hie.yaml",
"chars": 472,
"preview": "cradle:\n cabal:\n - path: \"lib\"\n component: \"lib:eclair-lang\"\n\n - path: \"src/eclair/Main.hs\"\n component:"
},
{
"path": "lib/Eclair/AST/Analysis.hs",
"chars": 17092,
"preview": "{-# LANGUAGE UndecidableInstances #-}\n\nmodule Eclair.AST.Analysis\n ( Result(..)\n , SemanticInfo(..)\n , SemanticErrors"
},
{
"path": "lib/Eclair/AST/Codegen.hs",
"chars": 6860,
"preview": "{-# LANGUAGE DerivingVia #-}\n\nmodule Eclair.AST.Codegen\n ( CodegenM\n , Env(..)\n , runCodegen\n , toTerm\n , project\n "
},
{
"path": "lib/Eclair/AST/IR.hs",
"chars": 5084,
"preview": "{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}\n\nmodule Eclair.AST.IR\n ( AST(.., PWildcard)\n , ASTF(.., PWildcardF"
},
{
"path": "lib/Eclair/AST/Lower.hs",
"chars": 7311,
"preview": "module Eclair.AST.Lower\n ( compileToRA\n ) where\n\nimport Prelude hiding (swap, project)\nimport qualified Data.Graph as "
},
{
"path": "lib/Eclair/AST/Transforms/ConstantFolding.hs",
"chars": 441,
"preview": "module Eclair.AST.Transforms.ConstantFolding\n ( transform\n ) where\n\nimport Eclair.AST.IR\nimport Eclair.Transform\n\ntran"
},
{
"path": "lib/Eclair/AST/Transforms/DeadCodeElimination.hs",
"chars": 714,
"preview": "module Eclair.AST.Transforms.DeadCodeElimination\n ( transform\n ) where\n\nimport Eclair.Transform\nimport Eclair.AST.Anal"
},
{
"path": "lib/Eclair/AST/Transforms/NormalizeRules.hs",
"chars": 905,
"preview": "module Eclair.AST.Transforms.NormalizeRules\n ( transform\n ) where\n\nimport Data.List (partition)\nimport Eclair.Transfor"
},
{
"path": "lib/Eclair/AST/Transforms/RemoveAliases.hs",
"chars": 2800,
"preview": "module Eclair.AST.Transforms.RemoveAliases\n ( transform\n ) where\n\nimport qualified Data.Map as M\nimport Eclair.Transfo"
},
{
"path": "lib/Eclair/AST/Transforms/ReplaceStrings.hs",
"chars": 1114,
"preview": "module Eclair.AST.Transforms.ReplaceStrings\n ( StringMap\n , transform\n ) where\n\nimport qualified Data.Map as Map\nimpo"
},
{
"path": "lib/Eclair/AST/Transforms.hs",
"chars": 1294,
"preview": "module Eclair.AST.Transforms\n ( simplify\n , ReplaceStrings.StringMap\n ) where\n\nimport Eclair.AST.IR\nimport Eclair.AST"
},
{
"path": "lib/Eclair/ArgParser.hs",
"chars": 2468,
"preview": "module Eclair.ArgParser\n ( parseArgs\n , parser\n , Config(..)\n , CompileConfig(..)\n , EmitKind(..)\n , Target(..)\n "
},
{
"path": "lib/Eclair/Common/Config.hs",
"chars": 739,
"preview": "module Eclair.Common.Config\n ( EmitKind(..)\n , CompileConfig(..)\n , Target(..)\n , Config(..)\n ) where\n\ndata EmitKin"
},
{
"path": "lib/Eclair/Common/Extern.hs",
"chars": 240,
"preview": "module Eclair.Common.Extern\n ( Extern(..)\n , ExternKind(..)\n ) where\n\nimport Eclair.Common.Id\n\n\ndata Extern = Extern "
},
{
"path": "lib/Eclair/Common/Id.hs",
"chars": 1120,
"preview": "module Eclair.Common.Id\n ( Id(..)\n , prependToId\n , appendToId\n , startsWithId\n , stripIdPrefixes\n , startsWithIdP"
},
{
"path": "lib/Eclair/Common/Literal.hs",
"chars": 285,
"preview": "module Eclair.Common.Literal\n ( Literal(..)\n ) where\nimport Prettyprinter (Pretty (pretty), dquotes)\n\ndata Literal\n ="
},
{
"path": "lib/Eclair/Common/Location.hs",
"chars": 3027,
"preview": "module Eclair.Common.Location\n ( NodeId(..)\n , Span(..)\n , SpanMap(..)\n , SourcePos(..)\n , SourceSpan(..)\n , inser"
},
{
"path": "lib/Eclair/Common/Operator.hs",
"chars": 1113,
"preview": "module Eclair.Common.Operator\n ( ArithmeticOp(..)\n , LogicalOp(..)\n , isEqualityOp\n , invertLogicalOp\n ) where\n\nimp"
},
{
"path": "lib/Eclair/Common/Pretty.hs",
"chars": 663,
"preview": "module Eclair.Common.Pretty\n ( module Eclair.Common.Pretty\n , module Prettyprinter\n , module Prettyprinter.Render.Tex"
},
{
"path": "lib/Eclair/Comonads.hs",
"chars": 522,
"preview": "module Eclair.Comonads\n ( module Eclair.Comonads\n ) where\n\n\ndata Triple a b c\n = Triple\n { tFst :: a\n , tSnd :: b\n "
},
{
"path": "lib/Eclair/EIR/IR.hs",
"chars": 5581,
"preview": "{-# LANGUAGE TemplateHaskell #-}\n\nmodule Eclair.EIR.IR\n ( EIR(..)\n , EIRF(..)\n , Relation\n , Op(..)\n , LogicalOp(.."
},
{
"path": "lib/Eclair/EIR/Lower/API.hs",
"chars": 13333,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.EIR.Lower.API\n ( CodegenInOutT\n , mkInOutState\n , cod"
},
{
"path": "lib/Eclair/EIR/Lower/Codegen.hs",
"chars": 5731,
"preview": "module Eclair.EIR.Lower.Codegen\n ( CodegenT\n , runCodegenM\n , LowerState(..)\n , Table(..)\n , Externals(..)\n , labe"
},
{
"path": "lib/Eclair/EIR/Lower/Externals.hs",
"chars": 2885,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.EIR.Lower.Externals\n ( createExternals\n ) where\n\nimpor"
},
{
"path": "lib/Eclair/EIR/Lower.hs",
"chars": 12570,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.EIR.Lower\n ( compileToLLVM\n ) where\n\nimport Prelude hi"
},
{
"path": "lib/Eclair/Error.hs",
"chars": 27100,
"preview": "{-# LANGUAGE MultiParamTypeClasses #-}\n{-# OPTIONS_GHC -fno-warn-orphans #-}\n\nmodule Eclair.Error\n ( EclairError(..)\n "
},
{
"path": "lib/Eclair/JSON.hs",
"chars": 1877,
"preview": "{-# LANGUAGE LinearTypes, MagicHash #-}\n-- | Helper module encoding Haskell values as JSON.\n-- Only a limited set of f"
},
{
"path": "lib/Eclair/LLVM/Allocator/Arena.hs",
"chars": 3023,
"preview": "{-# LANGUAGE GADTs #-}\n\nmodule Eclair.LLVM.Allocator.Arena\n ( Arena\n , allocator\n ) where\n\nimport Prelude hiding (voi"
},
{
"path": "lib/Eclair/LLVM/Allocator/Common.hs",
"chars": 5932,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n{-# LANGUAGE GADTs #-}\n\nmodule Eclair.LLVM.Allocator.Common\n ( Allocat"
},
{
"path": "lib/Eclair/LLVM/Allocator/Malloc.hs",
"chars": 583,
"preview": "module Eclair.LLVM.Allocator.Malloc\n ( Malloc\n , allocator\n ) where\n\nimport Eclair.LLVM.Allocator.Common\nimport Eclai"
},
{
"path": "lib/Eclair/LLVM/Allocator/Page.hs",
"chars": 1441,
"preview": "module Eclair.LLVM.Allocator.Page\n ( Page\n , allocator\n , roundToNearestPageSize -- for testing only\n ) where\n\nimpo"
},
{
"path": "lib/Eclair/LLVM/BTree/Bounds.hs",
"chars": 5531,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Bounds\n ( mkLinearSearchLowerBound\n , mkLin"
},
{
"path": "lib/Eclair/LLVM/BTree/Compare.hs",
"chars": 1598,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Compare\n ( mkCompare\n ) where\n\nimport Eclai"
},
{
"path": "lib/Eclair/LLVM/BTree/Create.hs",
"chars": 2234,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Create\n ( mkNodeNew\n , mkBtreeInit\n , mkBt"
},
{
"path": "lib/Eclair/LLVM/BTree/Destroy.hs",
"chars": 1603,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Destroy\n ( mkBtreeDestroy\n , mkBtreeClear\n "
},
{
"path": "lib/Eclair/LLVM/BTree/Find.hs",
"chars": 2320,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Find\n ( mkBtreeContains\n , mkBtreeFind\n ) "
},
{
"path": "lib/Eclair/LLVM/BTree/Insert.hs",
"chars": 15645,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Insert\n ( mkBtreeInsertValue\n , mkBtreeInse"
},
{
"path": "lib/Eclair/LLVM/BTree/Iterator.hs",
"chars": 5177,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Iterator\n ( mkIteratorInit\n , mkIteratorIni"
},
{
"path": "lib/Eclair/LLVM/BTree/Size.hs",
"chars": 1984,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.BTree.Size\n ( mkNodeCountEntries\n , mkBtreeIsEmpt"
},
{
"path": "lib/Eclair/LLVM/BTree/Types.hs",
"chars": 5520,
"preview": "module Eclair.LLVM.BTree.Types\n ( Meta(..)\n , Types(..)\n , SearchIndex\n , SearchType(..)\n , Sizes(..)\n , CGState(."
},
{
"path": "lib/Eclair/LLVM/BTree.hs",
"chars": 6053,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}\n\nmodule Eclair.L"
},
{
"path": "lib/Eclair/LLVM/Codegen.hs",
"chars": 2483,
"preview": "{-# LANGUAGE RoleAnnotations, PolyKinds #-}\n\nmodule Eclair.LLVM.Codegen\n ( module Eclair.LLVM.Codegen\n , module Eclair"
},
{
"path": "lib/Eclair/LLVM/Config.hs",
"chars": 1169,
"preview": "module Eclair.LLVM.Config\n ( Config(..)\n , ConfigT\n , runConfigT\n , MonadConfig(..)\n ) where\n\nimport qualified LLVM"
},
{
"path": "lib/Eclair/LLVM/Externals.hs",
"chars": 351,
"preview": "module Eclair.LLVM.Externals\n ( Externals(..)\n ) where\n\nimport Eclair.LLVM.Codegen (Operand)\n\n-- Functions that are de"
},
{
"path": "lib/Eclair/LLVM/Hash.hs",
"chars": 2021,
"preview": "{-# LANGUAGE TypeApplications, UndecidableInstances, TypeOperators, DefaultSignatures #-}\n\nmodule Eclair.LLVM.Hash\n ( H"
},
{
"path": "lib/Eclair/LLVM/HashMap.hs",
"chars": 7414,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Eclair.LLVM.HashMap\n ( HashMap(..)\n , Types(..)\n , codegen\n "
},
{
"path": "lib/Eclair/LLVM/Metadata.hs",
"chars": 962,
"preview": "module Eclair.LLVM.Metadata\n ( Metadata(..)\n , mkMeta\n , getIndex\n , getNumColumns\n ) where\n\nimport Eclair.RA.Index"
},
{
"path": "lib/Eclair/LLVM/Symbol.hs",
"chars": 3103,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Eclair.LLVM.Symbol\n ( Symbol(..)\n , codegen\n , sizeOf\n , dat"
},
{
"path": "lib/Eclair/LLVM/SymbolTable.hs",
"chars": 5430,
"preview": "{-# OPTIONS_GHC -Wno-unused-top-binds #-}\n{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.SymbolTab"
},
{
"path": "lib/Eclair/LLVM/Table.hs",
"chars": 1240,
"preview": "module Eclair.LLVM.Table\n ( Table(..)\n , IteratorParams(..)\n ) where\n\nimport Eclair.LLVM.Codegen (Operand, Type, Temp"
},
{
"path": "lib/Eclair/LLVM/Template.hs",
"chars": 6469,
"preview": "{-# LANGUAGE UndecidableInstances, FunctionalDependencies #-}\n\nmodule Eclair.LLVM.Template\n ( TemplateT\n , Template\n "
},
{
"path": "lib/Eclair/LLVM/Vector.hs",
"chars": 7155,
"preview": "{-# OPTIONS_GHC -Wno-unused-top-binds #-}\n{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\n\nmodule Eclair.LLVM.Vector\n "
},
{
"path": "lib/Eclair/LSP/Handlers/Diagnostics.hs",
"chars": 1884,
"preview": "module Eclair.LSP.Handlers.Diagnostics\n ( diagnosticsHandler\n , DiagnosticSource(..)\n , Severity(..)\n , Diagnostic(."
},
{
"path": "lib/Eclair/LSP/Handlers/DocumentHighlight.hs",
"chars": 2442,
"preview": "module Eclair.LSP.Handlers.DocumentHighlight\n ( documentHighlightHandler\n , DocHLResult(..)\n ) where\n\nimport Eclair\ni"
},
{
"path": "lib/Eclair/LSP/Handlers/Hover.hs",
"chars": 2473,
"preview": "module Eclair.LSP.Handlers.Hover\n ( hoverHandler\n , HoverResult(..)\n ) where\n\nimport Eclair\nimport Eclair.Error\nimpor"
},
{
"path": "lib/Eclair/LSP/Handlers.hs",
"chars": 284,
"preview": "module Eclair.LSP.Handlers\n ( module Eclair.LSP.Handlers.Hover\n , module Eclair.LSP.Handlers.Diagnostics\n , module Ec"
},
{
"path": "lib/Eclair/LSP/JSON.hs",
"chars": 4480,
"preview": "module Eclair.LSP.JSON\n ( responseToJSON\n , diagnosticToJSON\n , diagnosticSourceToJSON\n , severityToJSON\n , srcSpan"
},
{
"path": "lib/Eclair/LSP/Monad.hs",
"chars": 1315,
"preview": "module Eclair.LSP.Monad\n ( LspM\n , runLSP\n , liftLSP\n , getParams\n , module Eclair.LSP.VFS\n , posToOffset\n ) wher"
},
{
"path": "lib/Eclair/LSP/Types.hs",
"chars": 463,
"preview": "module Eclair.LSP.Types\n ( Command(..)\n , Response(..)\n ) where\n\nimport Eclair.Common.Location\nimport Eclair.LSP.Hand"
},
{
"path": "lib/Eclair/LSP/VFS.hs",
"chars": 1412,
"preview": "module Eclair.LSP.VFS\n ( VFS\n , VFST\n , runVFST\n , getVfsVar\n , vfsSetFile\n , vfsLookupFile\n , unsafeReadFromVFS\n"
},
{
"path": "lib/Eclair/LSP.hs",
"chars": 1941,
"preview": "module Eclair.LSP\n ( lspMain\n ) where\n\nimport Eclair (Parameters(..))\nimport Eclair.LSP.Handlers\nimport Eclair.LSP.Mon"
},
{
"path": "lib/Eclair/Parser.hs",
"chars": 10780,
"preview": "module Eclair.Parser\n ( parseFile\n , parseText\n , Parser\n , ParseError\n , CustomParseErr\n , ParsingError(..)\n ) w"
},
{
"path": "lib/Eclair/RA/Codegen.hs",
"chars": 11328,
"preview": "module Eclair.RA.Codegen\n ( CodegenM\n , runCodegen\n , LowerState(..)\n , mkLowerState\n , CGState(..)\n , CGInfo(..)\n"
},
{
"path": "lib/Eclair/RA/IR.hs",
"chars": 3077,
"preview": "{-# LANGUAGE TemplateHaskell #-}\n\nmodule Eclair.RA.IR\n ( Relation\n , RA(..)\n , RAF(..)\n , Alias\n , Clause\n , Actio"
},
{
"path": "lib/Eclair/RA/IndexSelection.hs",
"chars": 8803,
"preview": "module Eclair.RA.IndexSelection\n ( IndexMap\n , IndexSelector\n , Index(..)\n , SearchSignature(..)\n , Column\n , runI"
},
{
"path": "lib/Eclair/RA/Lower.hs",
"chars": 15375,
"preview": "\nmodule Eclair.RA.Lower ( compileToEIR ) where\n\nimport Prelude\nimport Data.Maybe (fromJust)\n\nimport qualified Data.List "
},
{
"path": "lib/Eclair/RA/Transforms/HoistConstraints.hs",
"chars": 4445,
"preview": "module Eclair.RA.Transforms.HoistConstraints\n ( transform\n ) where\n\nimport Eclair.Transform\nimport Eclair.RA.IR\nimport"
},
{
"path": "lib/Eclair/RA/Transforms.hs",
"chars": 300,
"preview": "module Eclair.RA.Transforms\n ( simplify\n ) where\n\nimport Eclair.Common.Location (NodeId(..))\nimport Eclair.RA.IR\nimpor"
},
{
"path": "lib/Eclair/Souffle/IR.hs",
"chars": 4937,
"preview": "module Eclair.Souffle.IR\n ( Souffle(..)\n , ConversionError(..)\n , toSouffle\n ) where\n\nimport qualified Eclair.AST.IR"
},
{
"path": "lib/Eclair/Transform.hs",
"chars": 2561,
"preview": "module Eclair.Transform\n ( Transform(..)\n , pureTransform\n , TransformM\n , runTransform\n , fixTransform\n , freshNo"
},
{
"path": "lib/Eclair/TypeSystem.hs",
"chars": 15327,
"preview": "module Eclair.TypeSystem\n ( Type(..)\n , TypeError(..)\n , Context(..)\n , getContextLocation\n , TypeInfo(..)\n , Defi"
},
{
"path": "lib/Eclair.hs",
"chars": 10993,
"preview": "{-# LANGUAGE GADTs, StandaloneDeriving #-}\n\nmodule Eclair\n ( parse\n , semanticAnalysis\n , typeCheck\n , emitDiagnosti"
},
{
"path": "lib/Prelude.hs",
"chars": 1617,
"preview": "module Prelude\n ( module Relude\n , module Control.Arrow\n , module Control.Monad.Writer.Strict\n , module Control.Mona"
},
{
"path": "src/eclair/Main.hs",
"chars": 1083,
"preview": "module Main (main) where\n\nimport Eclair.ArgParser\nimport Eclair.LSP\nimport Eclair\nimport GHC.IO.Encoding\nimport System.D"
},
{
"path": "tests/.gitignore",
"chars": 32,
"preview": "/**/.lit_test_times.txt\nOutput/\n"
},
{
"path": "tests/ast_transforms/constant_folding.eclair",
"chars": 1008,
"preview": "// RUN: split-file %s %t\n// RUN: %eclair compile --emit ast-transformed %t/program.eclair > %t/actual.out\n// RUN: diff %"
},
{
"path": "tests/ast_transforms/copy_propagation.eclair",
"chars": 1130,
"preview": "// RUN: split-file %s %t\n// RUN: %eclair compile --emit ast-transformed %t/program.eclair > %t/actual.out\n// RUN: diff %"
},
{
"path": "tests/ast_transforms/dead_code_elimination.eclair",
"chars": 1402,
"preview": "// RUN: split-file %s %t\n// RUN: %eclair compile %t/program1.eclair --emit ast-transformed > %t/actual1.out\n// RUN: diff"
},
{
"path": "tests/ast_transforms/remove_contradictions.eclair",
"chars": 529,
"preview": "// RUN: split-file %s %t\n// RUN: %eclair compile --emit ast-transformed %t/program.eclair > %t/actual.out\n// RUN: diff %"
},
{
"path": "tests/ast_transforms/shift_assignments.eclair",
"chars": 921,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ast-transformed %t/program1.eclair > %t/actual1.out\n// RUN: dif"
},
{
"path": "tests/check.sh",
"chars": 323,
"preview": "#!/bin/bash\n\ngrep -rE \"(fdescribe|fit)\" tests/eclair\n\nif [ \"$?\" == \"0\" ]; then\n echo \"Found disabled tests (marked with"
},
{
"path": "tests/eclair/Test/Eclair/ArgParserSpec.hs",
"chars": 2679,
"preview": "module Test.Eclair.ArgParserSpec\n ( module Test.Eclair.ArgParserSpec\n ) where\n\nimport Test.Hspec\nimport qualified Data"
},
{
"path": "tests/eclair/Test/Eclair/JSONSpec.hs",
"chars": 1134,
"preview": "{-# LANGUAGE QuasiQuotes #-}\n\nmodule Test.Eclair.JSONSpec\n ( module Test.Eclair.JSONSpec\n ) where\n\nimport Eclair.JSON\n"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/Allocator/MallocSpec.hs",
"chars": 2328,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.Allocator.MallocSpec\n ( module Test.Eclair.LLV"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/Allocator/PageSpec.hs",
"chars": 3964,
"preview": "{-# OPTIONS_GHC -Wno-deprecations -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.Allocator.PageSpec\n ( module"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/Allocator/Utils.hs",
"chars": 2769,
"preview": "{-# OPTIONS_GHC -Wno-deprecations #-}\nmodule Test.Eclair.LLVM.Allocator.Utils\n ( Bindings(..)\n , compileAllocatorCode\n"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/BTreeSpec.hs",
"chars": 27488,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.BTreeSpec\n ( module Test.Eclair.LLVM.BTreeSpec"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/HashMapSpec.hs",
"chars": 7457,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.HashMapSpec\n ( module Test.Eclair.LLVM.HashMap"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/HashSpec.hs",
"chars": 1925,
"preview": "module Test.Eclair.LLVM.HashSpec\n ( module Test.Eclair.LLVM.HashSpec\n ) where\n\nimport qualified Data.Set as Set\nimport"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/SymbolSpec.hs",
"chars": 2613,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.SymbolSpec\n ( module Test.Eclair.LLVM.SymbolSp"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/SymbolTableSpec.hs",
"chars": 9535,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.SymbolTableSpec\n ( module Test.Eclair.LLVM.Sym"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/SymbolUtils.hs",
"chars": 3790,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.SymbolUtils\n ( Bindings(..)\n , Symbol(..)\n ,"
},
{
"path": "tests/eclair/Test/Eclair/LLVM/VectorSpec.hs",
"chars": 7463,
"preview": "{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}\nmodule Test.Eclair.LLVM.VectorSpec\n ( module Test.Eclair.LLVM.VectorSp"
},
{
"path": "tests/eclair/Test/Eclair/LSP/HandlersSpec.hs",
"chars": 5463,
"preview": "module Test.Eclair.LSP.HandlersSpec\n ( module Test.Eclair.LSP.HandlersSpec\n ) where\n\nimport Eclair\nimport Eclair.TypeS"
},
{
"path": "tests/eclair/Test/Eclair/LSP/JSONSpec.hs",
"chars": 7714,
"preview": "{-# LANGUAGE QuasiQuotes #-}\n\nmodule Test.Eclair.LSP.JSONSpec\n ( module Test.Eclair.LSP.JSONSpec\n ) where\n\nimport qual"
},
{
"path": "tests/eclair/Test/Eclair/RA/IndexSelectionSpec.hs",
"chars": 9017,
"preview": "{-# LANGUAGE QuasiQuotes #-}\n\nmodule Test.Eclair.RA.IndexSelectionSpec\n ( module Test.Eclair.RA.IndexSelectionSpec\n ) "
},
{
"path": "tests/eclair/fixtures/lsp/document_highlight.eclair",
"chars": 134,
"preview": "@def edge(u32, u32).\n@def reachable(u32, u32).\n\nreachable(x, y) :-\n edge(x, y).\n\nreachable(x, y) :-\n edge(x, z),\n rea"
},
{
"path": "tests/eclair/fixtures/lsp/hover.eclair",
"chars": 193,
"preview": "@def edge(u32, u32) input.\n@def reachable(u32, u32) output.\n@def literal(string) output.\n\nreachable(x, y) :-\n edge(x, y"
},
{
"path": "tests/eclair/fixtures/lsp/invalid_syntax.eclair",
"chars": 69,
"preview": "@def number(u32) output.\n\nnumber(123, ).\nnumber(456).\nnumber(789, ).\n"
},
{
"path": "tests/eclair/fixtures/lsp/semantic_errors.eclair",
"chars": 57,
"preview": "@def wildcard_in_fact(u32) output.\n\nwildcard_in_fact(_).\n"
},
{
"path": "tests/eclair/fixtures/lsp/type_errors.eclair",
"chars": 173,
"preview": "@def edge(u32, u32).\n@def reachable(string, u32).\n@def literal(u32).\n\nreachable(x, y) :-\n edge(x, y).\n\nreachable(x, z) "
},
{
"path": "tests/eclair/fixtures/lsp/unparsable.eclair",
"chars": 130,
"preview": "@def edge(u32, u32).\n@def reachable(u32, u32).\n@def literal(string).\n\nreachable(x, y) :-\n\nreachable(x, z) :-\n 1.\n\nliter"
},
{
"path": "tests/eclair/test.hs",
"chars": 90,
"preview": "{-# OPTIONS_GHC -Wno-missing-export-lists #-}\n{-# OPTIONS_GHC -F -pgmF hspec-discover #-}\n"
},
{
"path": "tests/end_to_end/compile_and_run_native.eclair",
"chars": 1718,
"preview": "// This checks if eclair can be correctly compiled and linked with C code.\n\n// RUN: split-file %s %t\n// RUN: %eclair com"
},
{
"path": "tests/end_to_end/compile_and_run_wasm.eclair",
"chars": 3181,
"preview": "// This checks if eclair can be correctly compiled to WASM and used from JS.\n\n// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g"
},
{
"path": "tests/end_to_end/compile_and_run_with_extern.eclair",
"chars": 1821,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile %t/program.eclair > %t/program.ll\n// RUN: %clang -o %t/program -O0 %t/"
},
{
"path": "tests/hello.eclair",
"chars": 330,
"preview": "// This is mostly a sanity check that the test-suite works\n// (and that LLVM can compile to LLVM correctly).\n\n// RUN: %e"
},
{
"path": "tests/lit.cfg",
"chars": 1148,
"preview": "import subprocess\nimport lit.formats\nfrom lit.llvm.subst import ToolSubst\n\nconfig.name = \"Eclair integration tests\"\nconf"
},
{
"path": "tests/lowering/arithmetic.eclair",
"chars": 16601,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/clause_with_same_vars.eclair",
"chars": 11768,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/comparisons.eclair",
"chars": 13708,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/different_types.eclair",
"chars": 4640,
"preview": "// TODO add tests for caching mechanism (e.g. single_nonrecursive_rule test)\n\n// RUN: split-file %s %t\n\n// RUN: %eclair "
},
{
"path": "tests/lowering/extern_definitions.eclair",
"chars": 8687,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/multiple_clauses_same_name.eclair",
"chars": 9655,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/multiple_rule_clauses.eclair",
"chars": 10520,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/mutually_recursive_rules.eclair",
"chars": 27137,
"preview": "// TODO variant where one is recursive\n// TODO tests for rules with >2 clauses, ...\n\n// RUN: split-file %s %t\n\n// RUN: %"
},
{
"path": "tests/lowering/negation.eclair",
"chars": 10035,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/negation_with_wildcards.eclair",
"chars": 6027,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/no_top_level_facts.eclair",
"chars": 18540,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/recursive_mix_of_rules.eclair",
"chars": 1124,
"preview": "\n// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: di"
},
{
"path": "tests/lowering/single_non_recursive_rule.eclair",
"chars": 7223,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/single_recursive_rule.eclair",
"chars": 13809,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/stratification.eclair",
"chars": 2405,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/top_level_facts.eclair",
"chars": 5476,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --emit ra-transformed %t/program.eclair > %t/actual_ra.out\n// RUN: dif"
},
{
"path": "tests/lowering/wasm_codegen.eclair",
"chars": 1596,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile --target wasm32 --emit llvm %t/program.eclair > %t/actual_llvm.out\n// "
},
{
"path": "tests/parser/error_recovery.eclair",
"chars": 2411,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/parser/file_not_found.eclair",
"chars": 257,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/parser/valid.eclair",
"chars": 1708,
"preview": "// RUN: %eclair compile --emit ra-transformed %s | FileCheck %s\n// CHECK: project\n\n// u32\n@def fact1(u32) output.\n@def f"
},
{
"path": "tests/runtime/hashmap_test.eclair",
"chars": 4930,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile %t/program.eclair > %t/program.ll\n// RUN: %clang -O0 -o %t/program %t/"
},
{
"path": "tests/runtime/symbol_table_test.eclair",
"chars": 6587,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile %t/program.eclair > %t/program.ll\n// RUN: %clang -O0 -o %t/program %t/"
},
{
"path": "tests/runtime/vector_test.eclair",
"chars": 4135,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile %t/program.eclair > %t/program.ll\n// RUN: %clang -O0 -o %t/program %t/"
},
{
"path": "tests/semantic_analysis/cyclic_negation.eclair",
"chars": 1654,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/dead_internal_relation.eclair",
"chars": 796,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/invalid_extern_usage.eclair",
"chars": 8326,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/semantic_analysis/invalid_options_usage.eclair",
"chars": 867,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/semantic_analysis/invalid_wildcard_usage.eclair",
"chars": 8100,
"preview": "// NOTE: happy path is mostly skipped, this is tested implicitly by running\n// the compiler end-to-end in most other tes"
},
{
"path": "tests/semantic_analysis/no_output_relations.eclair",
"chars": 768,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/unconstrained_variables.eclair",
"chars": 1293,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/ungrounded_variables.eclair",
"chars": 13856,
"preview": "// NOTE: happy path is not tested, this is tested implicitly by running\n// the compiler end-to-end in most other tests\n\n"
},
{
"path": "tests/semantic_analysis/ungrounded_variables_arithmetic.eclair",
"chars": 1772,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/ungrounded_variables_comparisons.eclair",
"chars": 3575,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/semantic_analysis/ungrounded_variables_negations.eclair",
"chars": 1293,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/string_support/encode_decode_string.eclair",
"chars": 1684,
"preview": "// RUN: split-file %s %t\n\n// RUN: %eclair compile %t/program.eclair > %t/program.ll\n// RUN: %clang -O0 -o %t/program %t/"
},
{
"path": "tests/string_support/encode_decode_string_native.eclair",
"chars": 1938,
"preview": "// This checks if strings can be encoded / decoded between C <=> Eclair\n\n// RUN: split-file %s %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/string_support/encode_decode_string_wasm.eclair",
"chars": 2648,
"preview": "// This checks if strings can be encoded / decoded between JS <=> Eclair\n\n// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s "
},
{
"path": "tests/transpilation/souffle.eclair",
"chars": 1969,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/arg_count_mismatch.eclair",
"chars": 4066,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/arithmetic.eclair",
"chars": 3311,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/typesystem/comparisons.eclair",
"chars": 3895,
"preview": "// NOTE: happy path already tested in lowering tests.\n\n// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// "
},
{
"path": "tests/typesystem/duplicate_type_declarations.eclair",
"chars": 1326,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/extern_definitions.eclair",
"chars": 6123,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/typesystem/negation.eclair",
"chars": 926,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/typesystem/no_rules_for_type.eclair",
"chars": 127,
"preview": "// RUN: %eclair compile %s | FileCheck %s\n\n@def edge(u32, u32) input.\n@def chain(u32, u32, u32) input output.\n\n// CHECK:"
},
{
"path": "tests/typesystem/type_mismatch_in_rule.eclair",
"chars": 687,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/type_mismatch_in_rule_body.eclair",
"chars": 2597,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/type_mismatch_in_rule_head.eclair",
"chars": 2411,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/type_mismatch_top_level_atoms.eclair",
"chars": 2345,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/typed_holes.eclair",
"chars": 3321,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n//--- program1.eclair"
},
{
"path": "tests/typesystem/unification_failure.eclair",
"chars": 4348,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/unknown_atom_in_rule_body.eclair",
"chars": 1398,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/unknown_atom_in_rule_head.eclair",
"chars": 631,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/unknown_atoms.eclair",
"chars": 2054,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/unknown_top_level_atoms.eclair",
"chars": 868,
"preview": "// RUN: mkdir -p %t && sed s@TEST_DIR@%t@g %s > %t/input.test\n// RUN: split-file %t/input.test %t\n\n// RUN: %eclair compi"
},
{
"path": "tests/typesystem/valid.eclair",
"chars": 1329,
"preview": "// RUN: %eclair compile %s --emit ra-transformed | FileCheck %s\n// CHECK: project\n\n@def fact1(u32, string).\n@def fact2(s"
},
{
"path": "tests/utils/extract_snippet",
"chars": 179,
"preview": "#!/bin/bash\n# Print lines starting from a match on a pattern ($2), up to first empty line.\n# Use sed again to trim the t"
}
]
About this extraction
This page contains the full source code of the luc-tielen/eclair-lang GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 183 files (857.3 KB), approximately 275.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.