difftreelog
feat(macro) pass call location to builtins
in: master
8 files changed
cmds/jrsonnet-fmt/Cargo.tomldiffbeforeafterbothno changes
cmds/jrsonnet-fmt/src/main.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth5 equals,5 equals,6 error::{Error::*, Result},6 error::{Error::*, Result},7 operator::evaluate_mod_op,7 operator::evaluate_mod_op,8 parse_args, primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal,8 primitive_equals, push_frame, throw, with_state, ArrValue, Context, FuncVal,9 IndexableVal, Val,9 IndexableVal, Val,10};10};11use format::{format_arr, format_obj};11use format::{format_arr, format_obj};12use gcmodule::Cc;12use gcmodule::Cc;13use jrsonnet_interner::IStr;13use jrsonnet_interner::IStr;14use jrsonnet_parser::{ArgsDesc, ExprLocation};14use jrsonnet_parser::{ArgsDesc, ExprLocation};15use jrsonnet_types::ty;16use serde::Deserialize;15use serde::Deserialize;17use serde_yaml::DeserializingQuirks;16use serde_yaml::DeserializingQuirks;18use std::{17use std::{466 Ok(format!("{:x}", md5::compute(&str.as_bytes())))465 Ok(format!("{:x}", md5::compute(&str.as_bytes())))467}466}468467468#[jrsonnet_macros::builtin]469fn builtin_trace(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {469fn builtin_trace(#[location] loc: &ExprLocation, str: IStr, rest: Any) -> Result<Any> {470 parse_args!(context, "trace", args, 2, [470 eprint!("TRACE:");471 0, str: ty!(string) => Val::Str;472 1, rest: ty!(any);473 ], {474 eprint!("TRACE:");475 with_state(|s|{471 with_state(|s| {476 let locs = s.map_source_locations(&loc.0, &[loc.1]);472 let locs = s.map_source_locations(&loc.0, &[loc.1]);477 eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);473 eprint!(474 " {}:{}",475 loc.0.file_name().unwrap().to_str().unwrap(),476 locs[0].line477 );478 });478 });479 eprintln!(" {}", str);479 eprintln!(" {}", str);480 Ok(rest)480 Ok(rest) as Result<Any>481 })482}481}483482484#[jrsonnet_macros::builtin]483#[jrsonnet_macros::builtin]crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth16pub enum Error {16pub enum Error {17 #[error("intrinsic not found: {0}")]17 #[error("intrinsic not found: {0}")]18 IntrinsicNotFound(IStr),18 IntrinsicNotFound(IStr),19 #[error("argument reordering in intrisics not supported yet")]20 IntrinsicArgumentReorderingIsNotSupportedYet,211922 #[error("operator {0} does not operate on type {1}")]20 #[error("operator {0} does not operate on type {1}")]23 UnaryOperatorDoesNotOperateOnType(UnaryOpType, ValType),21 UnaryOperatorDoesNotOperateOnType(UnaryOpType, ValType),crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth312 Ok(body_ctx.extend(out, None, None, None))312 Ok(body_ctx.extend(out, None, None, None))313}313}314315#[macro_export]316macro_rules! parse_args {317 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [318 $($id: expr, $name: ident: $ty: expr $(=>$match: path)?);+ $(;)?319 ], $handler:block) => {{320 use $crate::{error::Error::*, throw, evaluate, push_description_frame, typed::CheckType};321322 let args = $args;323 if args.unnamed.len() + args.named.len() > $total_args {324 throw!(TooManyArgsFunctionHas($total_args));325 }326 $(327 if args.unnamed.len() + args.named.len() <= $id {328 throw!(FunctionParameterNotBoundInCall(stringify!($name).into()));329 }330 // Is named331 let $name = if $id >= $args.unnamed.len() {332 let named = &args.named[$id - $args.unnamed.len()];333 if &named.0 != stringify!($name) {334 throw!(IntrinsicArgumentReorderingIsNotSupportedYet);335 }336 &named.1337 } else {338 &$args.unnamed[$id]339 };340 let $name = push_description_frame(|| format!("evaluating builtin argument {}", stringify!($name)), || {341 let value = evaluate($ctx.clone(), &$name)?;342 $ty.check(&value)?;343 Ok(value)344 })?;345 $(346 let $name = if let $match(v) = $name {347 v348 } else {349 unreachable!();350 };351 )?352 )+353 ($handler as crate::Result<_>)354 }};355}356314crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth1use proc_macro2::Span;1use proc_macro2::Span;2use quote::quote;2use quote::quote;3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat};3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat, PatType};45fn is_location_arg(t: &PatType) -> bool {6 t.attrs.iter().any(|a| a.path.is_ident("location"))7}485#[proc_macro_attribute]9#[proc_macro_attribute]6pub fn builtin(10pub fn builtin(7 _attr: proc_macro::TokenStream,11 _attr: proc_macro::TokenStream,8 item: proc_macro::TokenStream,12 item: proc_macro::TokenStream,9) -> proc_macro::TokenStream {13) -> proc_macro::TokenStream {10 // syn::ItemFn::parse(input)14 // syn::ItemFn::parse(input)11 let fun: ItemFn = parse_macro_input!(item);15 let mut fun: ItemFn = parse_macro_input!(item);121617 let result = match fun.sig.output {18 syn::ReturnType::Default => panic!("builtin should return something"),19 syn::ReturnType::Type(_, ref ty) => ty.clone(),20 };2122 let params = fun23 .sig24 .inputs25 .iter()26 .map(|i| match i {27 FnArg::Receiver(_) => unreachable!(),28 FnArg::Typed(t) => t,29 })30 .filter(|a| !is_location_arg(a))31 .map(|t| {32 let ident = match &t.pat as &Pat {33 Pat::Ident(i) => i.ident.to_string(),34 _ => panic!("only idents supported yet"),35 };36 // TODO: Check if ty == Option<_>37 let optional = false;38 quote! {39 BuiltinParam {40 name: #ident,41 has_default: #optional,42 }43 }44 })45 .collect::<Vec<_>>();4647 let args = fun48 .sig49 .inputs50 .iter_mut()51 .map(|i| match i {52 FnArg::Receiver(_) => unreachable!(),53 FnArg::Typed(t) => t,54 })55 .map(|t| {56 let count_before = t.attrs.len();57 t.attrs.retain(|a| !a.path.is_ident("location"));58 let count_after = t.attrs.len();59 let is_location = count_before != count_after;60 if is_location {61 quote! {{62 loc63 }}64 } else {65 let ident = match &t.pat as &Pat {66 Pat::Ident(i) => i.ident.to_string(),67 _ => panic!("only idents supported yet"),68 };69 let ty = &t.ty;70 quote! {{71 let value = parsed.get(#ident).unwrap();7273 jrsonnet_evaluator::push_description_frame(74 || format!("argument <{}> evaluation", #ident),75 || <#ty>::try_from(value.evaluate()?),76 )?77 }}78 }79 }).collect::<Vec<_>>();80 13 let inner_name = Ident::new("inner", Span::call_site());81 let inner_name = Ident::new("inner", Span::call_site());14 let mut inner_fun = fun.clone();82 let mut inner_fun = fun.clone();15 inner_fun.sig.ident = inner_name.clone();83 inner_fun.sig.ident = inner_name.clone();16 let result = match fun.sig.output {17 syn::ReturnType::Default => panic!("builtin should return something"),18 syn::ReturnType::Type(_, ty) => ty,19 };2021 let params = fun22 .sig23 .inputs24 .iter()25 .map(|i| match i {26 FnArg::Receiver(_) => unreachable!(),27 FnArg::Typed(t) => t,28 })29 .map(|t| {30 let ident = match &t.pat as &Pat {31 Pat::Ident(i) => i.ident.to_string(),32 _ => panic!("only idents supported yet"),33 };34 // TODO: Check if ty == Option<_>35 let optional = false;36 quote! {37 BuiltinParam {38 name: #ident,39 has_default: #optional,40 }41 }42 });4344 let args = fun45 .sig46 .inputs47 .iter()48 .map(|i| match i {49 FnArg::Receiver(_) => unreachable!(),50 FnArg::Typed(t) => t,51 })52 .map(|t| {53 let ident = match &t.pat as &Pat {54 Pat::Ident(i) => i.ident.to_string(),55 _ => panic!("only idents supported yet"),56 };57 let ty = &t.ty;58 quote! {{59 let value = parsed.get(#ident).unwrap();6061 jrsonnet_evaluator::push_description_frame(62 || format!("argument <{}> evaluation", #ident),63 || <#ty>::try_from(value.evaluate()?),64 )?65 }}66 });678468 let attrs = &fun.attrs;85 let attrs = &fun.attrs;69 let vis = &fun.vis;86 let vis = &fun.vis;70 let name = &fun.sig.ident;87 let name = &fun.sig.ident;71 (quote! {88 (quote! {72 #(#attrs)*89 #(#attrs)*73 #vis fn #name(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {90 #vis fn #name(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {74 #inner_fun91 #inner_fun75 use jrsonnet_evaluator::function::BuiltinParam;92 use jrsonnet_evaluator::function::BuiltinParam;76 const PARAMS: &'static [BuiltinParam] = &[93 const PARAMS: &'static [BuiltinParam] = &[crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth191 write!(f, "}}")?;191 write!(f, "}}")?;192 }192 }193 ComplexValType::Union(v) => write_union(f, true, v.iter())?,193 ComplexValType::Union(v) => write_union(f, true, v.iter())?,194 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().map(|v| *v))?,194 ComplexValType::UnionRef(v) => write_union(f, true, v.iter().copied())?,195 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,195 ComplexValType::Sum(v) => write_union(f, false, v.iter())?,196 ComplexValType::SumRef(v) => write_union(f, false, v.iter().map(|v| *v))?,196 ComplexValType::SumRef(v) => write_union(f, false, v.iter().copied())?,197 };197 };198 Ok(())198 Ok(())199 }199 }flake.nixdiffbeforeafterboth1{1{2 description = "Rust jsonnet implementation";2 description = "Dotfiles manager";34 inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";3 inputs = {4 nixpkgs.url = "github:nixos/nixpkgs";5 inputs.flake-utils.url = "github:numtide/flake-utils";5 flake-utils.url = "github:numtide/flake-utils";66 naersk.url = "github:nix-community/naersk";7 rust-overlay.url = "github:oxalica/rust-overlay";8 pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";9 };7 outputs = { self, nixpkgs, flake-utils }:10 outputs = { self, nixpkgs, flake-utils, rust-overlay, pre-commit-hooks, naersk }:8 flake-utils.lib.eachDefaultSystem (system:11 flake-utils.lib.eachDefaultSystem (system:9 let12 let10 pkgs = nixpkgs.legacyPackages.${system};13 pkgs = import nixpkgs14 {15 inherit system;16 overlays = [ rust-overlay.overlay ];17 };18 rust = ((pkgs.rustChannelOf { date = "2021-11-11"; channel = "nightly"; }).default.override {19 extensions = [ "rust-src" ];20 });11 jrsonnet = pkgs.rustPlatform.buildRustPackage rec {21 naersk-lib = naersk.lib."${system}".override {12 pname = "jrsonnet";22 rustc = rust;13 version = "0.1.0";23 cargo = rust;14 src = self;15 cargoSha256 = "sha256-cez8pJ/uwj+PHAPQwpSB4CKaxcP8Uvv8xguOrVXR2xE=";16 };24 };17 in { 25 in26 rec {27 checks = {28 pre-commit-check = pre-commit-hooks.lib.${system}.run {29 src = ./.;30 hooks = {31 nixpkgs-fmt.enable = true;32 };33 };34 };18 defaultPackage = jrsonnet;35 defaultPackage = naersk-lib.buildPackage {36 pname = "dotman";37 root = ./.;38 buildInputs = with pkgs; [39 pkgs.sqlite40 ];41 };19 devShell = pkgs.mkShell {};42 devShell = pkgs.mkShell {43 inherit (checks.pre-commit-check) shellHook;44 nativeBuildInputs = with pkgs;[45 pkgs.binutils46 pkgs.pkgconfig47 pkgs.clang48 pkgs.x1149 pkgs.alsaLib50 pkgs.libudev51 pkgs.sqlite52 rust53 cargo-edit54 go-jsonnet55 ];56 };20 });57 }58 );