Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Package Manager & import changes #129

Merged
merged 17 commits into from
Feb 1, 2025
Merged

Package Manager & import changes #129

merged 17 commits into from
Feb 1, 2025

Conversation

nick-paul
Copy link
Collaborator

Overview

This PR introduces a simple package manager for aya. Aya can now download and install packages from the web and use them like regular libraries

This PR also includes major changes to importlib and import statements. See below for more information.

Demo

Example package (spec below): https://github.com/nick-paul/sample.aya

Aya's package manager is intended to be used directly in the REPL. To use the package manager, first import it:

aya> import pkg

Install a package

Install from a github stub or directly with a zip URL

aya> "nick-paul/sample.aya" pkg.add
[DEBUG/pkg]: Using pkg root dir /home/npaul/git/aya/pkg
[DEBUG/pkg]: Downloading file: https://github.com/nick-paul/sample.aya/archive/refs/heads/main.zip to /home/npaul/git/aya/pkg/tmp.zip
[DEBUG/pkg]: Unzipping /home/npaul/git/aya/pkg/tmp
[DEBUG/pkg]: Location of unzipped package: /home/npaul/git/aya/pkg/tmp/sample.aya-main
[DEBUG/pkg]: Got package data :{
  "0.1.0":version;
  "sample.aya":name;
  "nick-paul":author;
}
[DEBUG/pkg]: Moving files from /home/npaul/git/aya/pkg/tmp/sample.aya-main to /home/npaul/git/aya/pkg/sample.aya
[DEBUG/pkg]: Cleaning up...

Can also use direct zip URL if hosted elsewhere

aya> "https://github.com/nick-paul/sample.aya/archive/refs/heads/main.zip" pkg.add

Now you can import the package normally:

aya> import sample
aya> sample  
:{  
  {deg::num : pi(3.14159265),deg pi * 180 /}:deg_to_rad;  
  ...
}
aya> 90 sample.deg_to_rad
1.57079633

List installed packages

aya> pkg.list
sample.aya v0.1.0 (nick-paul)

Run package tests

aya> "sample.aya" pkg.test
Running test: /home/npaul/git/aya/pkg/sample.aya/test/tests.aya

Run package entrypoint

This is useful if a package is intended to be a standalone app or demo instead of a library

aya> "sample.aya" pkg.run
== Angle Conversion Utility ==
Enter an angle in degrees: 90
Radians: 1.57079633
Conversion complete.

Update an existing package

aya> "sample.aya" pkg.update
[DEBUG/pkg]: Using pkg root dir /home/npaul/git/aya/pkg
[DEBUG/pkg]: Downloading file: https://github.com/nick-paul/sample.aya/archive/refs/heads/main.zip to /home/npaul/git/aya/pkg/tmp.zip
[DEBUG/pkg]: Unzipping /home/npaul/git/aya/pkg/tmp
[DEBUG/pkg]: Location of unzipped package: /home/npaul/git/aya/pkg/tmp/sample.aya-main
[DEBUG/pkg]: Got package data :{
  "0.1.0":version;
  "sample.aya":name;
  "nick-paul":author;
}
[DEBUG/pkg]: Moving files from /home/npaul/git/aya/pkg/tmp/sample.aya-main to /home/npaul/git/aya/pkg/sample.aya
[DEBUG/pkg]: Cleaning up...

Remove a package

aya> "sample.aya" pkg.remove
aya> pkg.list

Package development

No specific commands exist for developing a package yet but you can simply create a repo in the pkg/ folder and it will be available.

  • TODO: Add pkg.init to add files (pkg.aya, package.json, src/, ect) when creating a package

Package Spec

What is an aya package?

Example: nick-paul/sample.aya
More complicated example: nick-paul/trimesh.aya

  • __pkg__.aya: The entrypoint for the package. This file should bring package variables into scope. It should generally only have import/require statements in it
  • package.json: Package metadata
    • name: The package name
      • Currently I'm using the same naming convention as Julia. That is, packages have a .aya extension
    • version: Version is major.minor.patch format
    • author: Package author
  • src/: Location of aya source files
  • test/: Location of aya test files. All aya files in this folder will be ran when using pkg.test

Changes to importlib

importlib now defines two global keywords: import & require

import

import <module>: import the module and assign it to the module name

Example

Assume "sample.aya" has variables "foo" and "bar"

import sample will define the variable sample to the dict :{ ...:foo ...:bar}.
Use sample.foo & sample.bar to access imported names

Valid import statements

  • Standard imports: Search for files in "<importlib._path>/.aya"

    • import "example"
    • import "example.aya" (extension optional, no extension preferred)
  • Relative imports: Search for files relative to the file with the import statement

    • import ".relative"
    • import ".relative.aya" (extension optional, no extension preferred)
    • import ".src/relative.aya"
  • Package imports: If the import points to a directory, it will look for <path>/__pkg__.aya

    • import "src/package" (assumes src/package/__pkg__.aya exists)
  • Identifier imports: Identifiers will be converted to strings before importing

    • import example (same as import "example")
    • import .example (ERROR: Will import "example" not ".example")
    • Use with a SINGLE IDENTIFIER ONLY! Anything after the first identifier is treated as
      a nomal aya expression
      • import foo.bar (Parsed as {(import foo) .bar} )
      • import foo/bar (Parsed as {(import foo) / bar} )
  • Multiple imports: Wrap multiple imports in a block

    • import {foo bar}
    • import {example "./src/foo"} (same rules as above apply, can be an identifier or string)

require

Require is similar to import but imports names directly into the current scope.
You can specify which names to import or import all with a wildcard.
When using the wildcard, names with a leading underscore will not be imported

Example

Assume "sample.aya" has variables "foo", "bar", and "_baz"

  • require sample {foo} will bring foo into the current scope. sample and sample.bar are undefined
  • require sample {foo bar} will bring foo and bar into the current scope
  • require sample * will bring foo and bar into the current scope. _baz will not be imported
    since it has a leading underscore
  • require sample {foo _baz} will bring foo and _baz into the current scope even though _baz has a leading underscore

Valid require statements

  • Bring sin, cos, and tan into scope
    • require math {sin cos tan}
    • require ".math" {sin cos tan}
  • Like imports, strings and identifiers are interchangeable (identifiers preferred when possible)
    • require "math" {"sin" "cos" "tan"}
    • require "./src/math" {"sin" "cos" "tan"}
  • Require * will bring all variables that do not start with a leading _ into scope
    • require math *
    • require "./src/math" *

@nick-paul nick-paul marked this pull request as ready for review January 26, 2025 19:07
@nick-paul nick-paul merged commit 86e15d6 into master Feb 1, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant